# YouTube Video Transcript (`starvibe/youtube-video-transcript`) Actor

This Apify Actor extracts full transcripts (with timestamps) and metadata from YouTube videos, including title, description, upload date, views, likes, channel info, and duration

- **URL**: https://apify.com/starvibe/youtube-video-transcript.md
- **Developed by:** [starvibe](https://apify.com/starvibe) (community)
- **Categories:** Videos, Agents, Social media
- **Stats:** 8,262 total users, 2,073 monthly users, 100.0% runs succeeded, 133 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$5.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 and Metadata Extractor - Download Video Subtitles & Channel Data

Extract YouTube video transcripts, subtitles, and metadata effortlessly with this powerful Apify Actor. Download structured data from individual videos or entire channels, including titles, view counts, timestamps, and complete transcripts in multiple languages. Perfect for content analysis, research, SEO, and data mining.

### Key Features

- **Extract YouTube Transcripts**: Download complete video subtitles and captions in multiple languages
- **Channel Scraping**: Fetch data from entire YouTube channels with customizable date ranges
- **Rich Metadata**: Get video titles, descriptions, view counts, likes, comments, video thumbnails, channel thumbnails, channel usernames, and more
- **Multi-language Support**: Access transcripts in any available language using ISO 639-1 codes
- **Auto-generated Captions**: Fallback to auto-generated subtitles when manual captions aren't available
- **Free Plan Limits**: Free users can fetch up to 50 transcripts per day (resets at 00:00 UTC)
- **Structured JSON Output**: Export data in clean, structured JSON format for easy integration
- **Date Filtering**: Filter channel videos by publication date range
- **No Scraping Required**: Reliable data extraction without complex YouTube scraping

### Use Cases

- **Content Research**: Analyze video content and extract insights from transcripts
- **SEO & Marketing**: Extract video metadata for competitive analysis and keyword research
- **Academic Research**: Gather YouTube data for studies and analysis
- **Content Creation**: Repurpose video transcripts for blog posts, articles, or social media
- **Data Analysis**: Build datasets from YouTube channels for AI/ML training or analytics
- **Accessibility**: Convert video content to text format for accessibility purposes
- **Media Monitoring**: Track and analyze content from specific channels over time

### Input

Provide either a YouTube video URL (for single video) or a channel URL (to fetch multiple videos). The Actor requires the following fields, defined in input\_schema.json. Provide exactly one of youtube\_url or channel\_url; the backend will validate and ignore inapplicable fields:

| Field       | Type    | Description                                                                                                                                                                                                                   | Required                                 |
| ----------- | ------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------------------------------- |
| youtube\_url | String  | The URL of the YouTube video (e.g., https://www.youtube.com/watch?v=dQw4w9WgXcQ). Use for single video fetch, paired with language.                                                                                           | No (mutually exclusive with channel\_url) |
| language    | String  | The transcript language in ISO 639-1 format (e.g., en).                                                                                                                                                                       | No                                       |
| channel\_url | String  | The URL of the YouTube channel (e.g., https://www.youtube.com/@taostats or https://www.youtube.com/channel/UCxxxxxxxxxxxxxxxxxxxxxx). Use to fetch videos from the channel, paired with max\_videos, start\_date, and end\_date. | No (mutually exclusive with youtube\_url) |
| max\_videos  | Integer | Maximum number of videos to fetch from the channel (default: 10, range: 1-200). Only applicable with channel\_url.                                                                                                              | No                                       |
| start\_date  | String  | Start date for filtering channel videos (Expected ISO 8601 format). Only applicable with channel\_url; backend uses 30 days ago if blank. Ensure end\_date >= start\_date.                                                             | No                                       |
| end\_date    | String  | End date for filtering channel videos (Expected ISO 8601 format). Only applicable with channel\_url; backend uses today if blank. Ensure end\_date >= start\_date.                                                                     | No                                       |
| include\_transcript\_text | Boolean | Include the full transcript as a plain string without timestamps (`transcript_text` field). Default is `false` to reduce response size. Enable this if you need the transcript as a single text block.               | No                                       |

**Example Input (Single Video)**:

```json
{
  "youtube_url": "https://www.youtube.com/watch?v=6EeDKyS7pV8",
  "language": "en"
}
```

**Example Input (Channel Videos)**:

```json
{
  "channel_url": "https://www.youtube.com/@taostats",
  "max_videos": 10,
  "language": "en",
  "start_date": "2025-08-17",
  "end_date": "2025-09-16"
}
```

### Output

The Actor saves data to the Apify dataset in a structured JSON format, as defined in dataset\_schema.json. For single video, output is an array with one item; for channel, it's an array of video items. The output includes:

| Field               | Type    | Description                                                                                   |
| ------------------- | ------- | --------------------------------------------------------------------------------------------- |
| video\_id            | String  | The unique identifier of the YouTube video.                                                   |
| title               | String  | The title of the YouTube video.                                                               |
| channel\_name        | String  | The name of the YouTube channel.                                                              |
| channel\_id          | String  | The unique identifier of the YouTube channel.                                                 |
| channel\_username    | String  | The channel username derived from the YouTube custom URL or handle.                           |
| channel\_thumbnail   | String  | The URL of the channel thumbnail image.                                                       |
| subscriber\_count    | Integer | The number of subscribers on the YouTube channel.                                             |
| timestamp           | Integer | The Unix timestamp of when the video was published.                                           |
| published\_at        | String  | The UTC date and time of video upload (format: YYYY-MM-DD HH:MM:SSZ).                         |
| view\_count          | Integer | The number of views the video has received.                                                   |
| like\_count          | Integer | The number of likes the video has received.                                                   |
| comment\_count       | Integer | The number of comments on the video.                                                          |
| transcript          | Array   | An array of transcript segments, each with text, start, and end timestamps.                   |
| transcript\_text     | String  | Full transcript as a plain string without timestamps. Only included when `include_transcript_text` is `true`. |
| url                 | String  | The URL of the YouTube video.                                                                 |
| language            | String  | The primary language of the transcript (e.g., en for English).                                |
| duration\_seconds    | Integer | The total duration of the video in seconds.                                                   |
| description         | String  | The video description.                                                                        |
| thumbnail           | String  | The URL of the video thumbnail image.                                                         |
| status              | String  | Processing status (e.g., "success").                                                          |
| message             | String  | Status message about the transcript fetch operation.                                          |
| available\_languages | Array   | List of all available transcript languages for the video.                                     |
| selected\_language   | String  | The language that was selected for the transcript.                                            |
| is\_auto\_generated   | Boolean | Whether the transcript is auto-generated or manually created.                                 |
| geo\_restrict        | String  | Geographic restrictions on the video, if any.                                                 |

#### Free Plan Limit Notice

Free users are limited to 50 transcripts per day (reset at 00:00 UTC). When the limit is reached, the API returns a payload with `error: "limit_exceeded"`. The Actor logs a status message and stores an error item in the dataset with `status: "error"` and the limit message.

**Sample Output Example:**

```json
[
  {
    "channel_id": "UC7TghOL755nBk7HelHoi9LQ",
    "channel_name": "CoinDesk",
    "channel_thumbnail": "https://yt3.googleusercontent.com/example-channel-thumbnail=s800-c-k-c0x00ffffff-no-rj",
    "channel_username": "CoinDesk",
    "comment_count": 1,
    "duration_seconds": 86,
    "language": "en",
    "like_count": 14,
    "timestamp": 1759059043,
    "title": "This Bitcoin developer is on a power trip",
    "transcript": [
      {
        "end": 2.639,
        "start": 0.56,
        "text": "Then the last one which is kind of the"
      },
      {
        "end": 4.64,
        "start": 2.639,
        "text": "one that I kind of but my head against"
      },
      {
        "end": 7.359,
        "start": 4.64,
        "text": "Luke with over the past three years was"
      },
      {
        "end": 10.24,
        "start": 7.359,
        "text": "the BIPS repo. So what happened is"
      },
      {
        "end": 12.16,
        "start": 10.24,
        "text": "because Luke is such a difficult person"
      },
      {
        "end": 14.639,
        "start": 12.16,
        "text": "to work with and he loves having"
      },
      {
        "end": 18,
        "start": 14.639,
        "text": "positions of authority when he was uh"
      },
      {
        "end": 21.279,
        "start": 18,
        "text": "one of the uh editors of the BIPS the"
      },
      {
        "end": 23.119,
        "start": 21.279,
        "text": "Bitcoin improvement proposal repo which"
      },
      {
        "end": 24.72,
        "start": 23.119,
        "text": "is where people submit new ideas which"
      },
      {
        "end": 26.8,
        "start": 24.72,
        "text": "are then cataloged and numbered. he"
      },
      {
        "end": 29.439,
        "start": 26.8,
        "text": "became so difficult to work with um and"
      },
      {
        "end": 31.519,
        "start": 29.439,
        "text": "coupled with people just naturally kind"
      },
      {
        "end": 35.2,
        "start": 31.519,
        "text": "of leaving the space that um after a few"
      },
      {
        "end": 38.64,
        "start": 35.2,
        "text": "years Luke found himself originally one"
      },
      {
        "end": 41.2,
        "start": 38.64,
        "text": "of several BIP editors now the only BIP"
      },
      {
        "end": 44.559,
        "start": 41.2,
        "text": "editor from 2023 till I think mid24 and"
      },
      {
        "end": 49.28,
        "start": 44.559,
        "text": "during this time Luke refused to give uh"
      },
      {
        "end": 51.12,
        "start": 49.28,
        "text": "BIP numbers to certain proposals"
      },
      {
        "end": 54.8,
        "start": 51.12,
        "text": "including popular ones like like OPC cat"
      },
      {
        "end": 57.6,
        "start": 54.8,
        "text": "and there is a well docu documented um"
      },
      {
        "end": 59.76,
        "start": 57.6,
        "text": "push and pull an argument um people"
      },
      {
        "end": 62.079,
        "start": 59.76,
        "text": "saying Luke please just give a number"
      },
      {
        "end": 64.32,
        "start": 62.079,
        "text": "and Luke saying that he doesn't think"
      },
      {
        "end": 67.2,
        "start": 64.32,
        "text": "these are serious proposals that is off"
      },
      {
        "end": 69.84,
        "start": 67.2,
        "text": "that is a very very false and uh"
      },
      {
        "end": 72.4,
        "start": 69.84,
        "text": "ridiculous statement to make then when"
      },
      {
        "end": 75.76,
        "start": 72.4,
        "text": "BIP editors were added uh a lot of the"
      },
      {
        "end": 78.88,
        "start": 75.76,
        "text": "uh BIP numbers were uh they started a"
      },
      {
        "end": 80.799,
        "start": 78.88,
        "text": "lot of the the process resumed again but"
      },
      {
        "end": 83.36,
        "start": 80.799,
        "text": "it basically required taking it uh away"
      },
      {
        "end": 87.84,
        "start": 83.36,
        "text": "from just Luke's sole free."
      }
    ],
    "transcript_text": "Then the last one which is kind of the one that I kind of but my head against Luke with over the past three years was the BIPS repo. So what happened is because Luke is such a difficult person to work with and he loves having positions of authority when he was uh one of the uh editors of the BIPS the Bitcoin improvement proposal repo which is where people submit new ideas which are then cataloged and numbered. he became so difficult to work with um and coupled with people just naturally kind of leaving the space that um after a few years Luke found himself originally one of several BIP editors now the only BIP editor from 2023 till I think mid24 and during this time Luke refused to give uh BIP numbers to certain proposals including popular ones like like OPC cat and there is a well docu documented um push and pull an argument um people saying Luke please just give a number and Luke saying that he doesn't think these are serious proposals that is off that is a very very false and uh ridiculous statement to make then when BIP editors were added uh a lot of the uh BIP numbers were uh they started a lot of the the process resumed again but it basically required taking it uh away from just Luke's sole free.",
    "published_at": "2025-09-28T11:30:43Z",
    "url": "https://www.youtube.com/watch?v=sGYS42SjRkg",
    "video_id": "sGYS42SjRkg",
    "view_count": 730,
    "geo_restrict": null,
    "status": "success",
    "message": "Successfully fetched the transcript for the video with ID 'sGYS42SjRkg'",
    "available_languages": [
      "English (auto-generated)"
    ],
    "selected_language": "English (auto-generated)",
    "is_auto_generated": true,
    "description": "🎧 Catch the latest episode of 'BITCOIN SEASON 2: Inside the Mind of Luke Dashjr, Bitcoin's Most Polarizing Developer,' in partnership with Blockspace Media!",
    "thumbnail": "https://i.ytimg.com/vi/sGYS42SjRkg/maxresdefault.jpg"
  }
]
```

### Why Use This Actor?

- **Fast & Efficient**: Extract YouTube video and channel data in seconds without manual scraping
- **Flexible Data Collection**: Fetch single videos or bulk extract from entire channels with date filtering
- **Comprehensive Data**: Get transcripts, metadata, engagement metrics, and thumbnails in one request
- **Reliable Performance**: Built-in validation, error handling, and automatic language fallback
- **Easy Integration**: Clean JSON output works seamlessly with any data pipeline or analytics tool
- **Cost-Effective**: Pay-per-result pricing means you only pay for successful extractions

### Pricing

This Actor uses a **Pay Per Result (PPR)** billing model:

- **$5.00 per 1,000 results**
- Each video processed (whether from a single video URL or channel URL) counts as one result
- You are only charged for successfully processed videos that are saved to your dataset
- Failed requests do not count towards your usage

**Example**: If you fetch 10 videos from a channel, you will be charged for 10 results ($0.05).

### Troubleshooting

#### Invalid URL Format

**Problem**: Error message about invalid URL format.

**Solution**: Ensure your URL follows one of these formats:

- Video URL: `https://www.youtube.com/watch?v=VIDEO_ID`
- Channel URL (handle): `https://www.youtube.com/@channelhandle`
- Channel URL (ID): `https://www.youtube.com/channel/CHANNEL_ID`

#### Transcript Not Available

**Problem**: Video returns no transcript or "transcript not available" error.

**Solution**:

- Not all videos have transcripts/subtitles available
- Check if the video has captions enabled on YouTube
- Try a different language code if the requested language is not available
- Check the `available_languages` field in the output to see what languages are available

#### Language Not Available

**Problem**: Requested language is not available for the video.

**Solution**:

- The Actor will attempt to fetch the transcript in the requested language
- If not available, it may fall back to auto-generated captions or other available languages
- Check the `available_languages` field in the output to see supported languages
- Use ISO 639-1 language codes (e.g., `en`, `es`, `fr`)

#### No Videos Found for Channel

**Problem**: Channel URL provided but no videos are returned.

**Solution**:

- Verify the channel URL is correct and publicly accessible
- Check your `start_date` and `end_date` range - there may be no videos published in that period
- Adjust the `max_videos` parameter if needed (default: 10, range: 1-200)
- Some channels may have restricted access or no public videos

#### Date Range Errors

**Problem**: Error about invalid date range.

**Solution**:

- Ensure `end_date` is greater than or equal to `start_date`
- Use ISO 8601 date format: `YYYY-MM-DD`
- If dates are not provided, the Actor uses the last 30 days by default
- Example valid range: `"start_date": "2025-08-17"`, `"end_date": "2025-09-16"`

#### Channel Videos vs Single Video

**Problem**: Confused about which input fields to use.

**Solution**:

- Use `youtube_url` + `language` for fetching a single video
- Use `channel_url` + `max_videos` + `start_date` + `end_date` + `language` for fetching multiple videos from a channel
- Do not provide both `youtube_url` and `channel_url` - they are mutually exclusive

# Actor input Schema

## `youtube_url` (type: `string`):

Enter a valid YouTube video URL (e.g., https://www.youtube.com/watch?v=video\_id, https://youtu.be/video\_id, or https://www.youtube.com/shorts/video\_id). Use this for fetching a single video, paired with 'language' for transcript. Do not combine with channel filtering fields.

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

Language of the subtitles in ISO 639-1 format, e.g., `en`, `fr`. Applicable to both youtube\_url and channel\_url. Leave blank for default language.

## `channel_url` (type: `string`):

Enter a valid YouTube channel URL (e.g., https://www.youtube.com/channel/UCxxxxxxxxxxxxxxxxxxxxxx or https://www.youtube.com/@channelhandle). Use this to fetch videos from the channel, paired with 'max\_videos', 'start\_date', and 'end\_date' for limiting and filtering results.

## `max_videos` (type: `integer`):

Maximum number of videos to fetch from the channel (optional, default: 10, range: 1 to 200). Only applicable and used with channel\_url; ignored for youtube\_url. Combine with start\_date/end\_date for filtered results.

## `start_date` (type: `string`):

Start date for filtering videos by upload date (format: YYYY-MM-DD or ISO 8601, optional). Only applicable and used with channel\_url; ignored for youtube\_url. Videos uploaded on or after this date will be fetched.

## `end_date` (type: `string`):

End date for filtering videos by upload date (format: YYYY-MM-DD or ISO 8601, optional). Only applicable and used with channel\_url; ignored for youtube\_url. Videos uploaded on or before this date will be fetched.

## `include_transcript_text` (type: `boolean`):

Include the full transcript as a plain string without timestamps (transcript\_text field). Default is off to reduce response size. Enable this if you need the transcript as a single text block.

## Actor input object example

```json
{
  "youtube_url": "https://www.youtube.com/watch?v=gN07gbipMoY",
  "channel_url": "https://www.youtube.com/@taostats",
  "max_videos": 10,
  "include_transcript_text": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing video transcripts 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 = {
    "youtube_url": "https://www.youtube.com/watch?v=gN07gbipMoY",
    "channel_url": "https://www.youtube.com/@taostats"
};

// Run the Actor and wait for it to finish
const run = await client.actor("starvibe/youtube-video-transcript").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 = {
    "youtube_url": "https://www.youtube.com/watch?v=gN07gbipMoY",
    "channel_url": "https://www.youtube.com/@taostats",
}

# Run the Actor and wait for it to finish
run = client.actor("starvibe/youtube-video-transcript").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 '{
  "youtube_url": "https://www.youtube.com/watch?v=gN07gbipMoY",
  "channel_url": "https://www.youtube.com/@taostats"
}' |
apify call starvibe/youtube-video-transcript --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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