# Youtube Text & Metadata Scraper (`ilborso/youtube-text-scraper`) Actor

Extract YouTube transcripts, subtitles, video metadata, hashtags, thumbnails, views, duration, and release dates from YouTube videos using either a search query or a list of direct YouTube URLs. It helps you turn YouTube search results and specific video links into structured JSON data

- **URL**: https://apify.com/ilborso/youtube-text-scraper.md
- **Developed by:** [Fabio Borsotti](https://apify.com/ilborso) (community)
- **Categories:** AI, Lead generation, Developer tools
- **Stats:** 32 total users, 9 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.90 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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?

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 Actor

Extract YouTube transcripts, subtitles, video metadata, hashtags, thumbnails, views, duration, and release dates from YouTube videos using either a search query or a list of direct YouTube URLs. This YouTube transcript scraper helps you turn YouTube search results and specific video links into structured JSON data for research, SEO, lead generation, monitoring, and content analysis.

### What does YouTube Transcript Scraper do?

YouTube Transcript Scraper is an APIFY Actor that can search YouTube videos by keyword, apply a time filter, collect video metadata, and retrieve the first available transcript based on your preferred language order. It can also process direct YouTube video URLs and include those videos in the final output.

This Actor is ideal if you want to:

- train RAG algorithms for AI
- scrape YouTube transcripts
- extract YouTube subtitles
- collect YouTube video metadata
- monitor YouTube search results
- build datasets from YouTube videos
- automate YouTube content research
- extract transcripts from specific YouTube videos

The Actor uses:

- `pytubefix` for YouTube search and metadata extraction
- `youtube-transcript-api` for transcript and subtitle retrieval
- Scrape.do as a proxy layer

### Why use this YouTube scraper?

If you work with YouTube data, transcripts are one of the most valuable sources of structured content. Video transcripts help you analyze what creators actually say, not just what appears in titles and descriptions.

This Actor is useful because it supports two collection modes in the same run:

- search by keyword using `query`
- direct processing of specific YouTube videos using `direct_url`

This makes it practical both for broad monitoring and for targeted transcript extraction from known videos.

#### Common use cases

- SEO research for YouTube videos and keywords
- competitor monitoring on YouTube
- AI training and text dataset preparation
- content repurposing from video to text
- lead generation from niche YouTube channels
- trend monitoring by date range
- transcript-based topic clustering
- YouTube video catalog enrichment
- transcript extraction from manually selected videos

### What data does the Actor extract?

For each processed YouTube video, the Actor can return:

- YouTube video ID
- video title
- video URL
- channel name
- channel URL
- transcript text with timestamps
- available subtitles metadata
- video view count
- video duration in seconds
- release date
- thumbnail URL
- keywords / hashtags
- likes count
- comments count
- video description
- video categories
- live stream indicator
- geographical availability
- video language
- chapters (if available)
- series, season, and episode information

**Note:** By default, the Actor extracts transcript only and returns empty values for metadata fields. To include video metadata and subtitles, set `enableMetadata: true` in the input. See the "Metadata Retrieval Strategy" section for details.

#### Output Fields Reference

| Field | Type | Description | Availability |
|-------|------|-------------|--------------|
| `id` | string | YouTube video ID | Always |
| `title` | string | Video title (short form) | Always |
| `url` | string | YouTube video watch URL | Always |
| `autor` | string | Channel/creator name (from search) | Always |
| `text` | string | Video transcript with timestamps in format \[MM:SS] | Always if available |
| `channel_name` | string | Channel/uploader name | With enableMetadata = true |
| `channel_url` | string | URL to the channel page | With enableMetadata = true |
| `video_title` | string | Full video title | With enableMetadata = true |
| `video_url` | string | YouTube video URL | With enableMetadata = true |
| `views_count` | integer | Total number of video views | With enableMetadata = true |
| `duration_seconds` | integer | Video duration in seconds | With enableMetadata = true |
| `release_date` | string | Video publish date in format YYYY-MM-DD | With enableMetadata = true |
| `thumbnail_url` | string | URL to the video thumbnail image | With enableMetadata = true |
| `hashtags` | array | Hashtags associated with the video | With enableMetadata = true |
| `like_count` | integer | Number of likes on the video | With enableMetadata = true |
| `comment_count` | integer | Number of comments on the video | With enableMetadata = true |
| `description` | string | Full video description text | With enableMetadata = true |
| `keywords` | array | Keywords associated with the video | With enableMetadata = true |
| `categories` | array | Video categories/topics | With enableMetadata = true |
| `is_live` | boolean | Whether the video is a live stream | With enableMetadata = true |
| `availability` | string | Geographical availability status | With enableMetadata = true |
| `language` | string | Primary language code of the video | With enableMetadata = true |
| `chapters` | array | Chapter markers with timestamps (if available) | With enableMetadata = true |
| `series` | string | Series name if video is part of a series | With enableMetadata = true |
| `season` | integer | Season number if video is part of a series | With enableMetadata = true |
| `episode` | integer | Episode number if video is part of a series | With enableMetadata = true |
| `subtitles` | array | Available subtitle/transcript languages with metadata | With enableMetadata = true |

### Why this Actor is useful

This YouTube Transcript Scraper is useful when you need structured YouTube data without building and maintaining your own scraping workflow. It is designed for users who want fast access to transcript-rich video data in a reusable JSON format.

Compared with a basic YouTube metadata scraper, this Actor focuses on transcript extraction and subtitle discovery, which makes it especially helpful for:

- content intelligence
- SEO workflows
- machine learning pipelines
- research automation
- enrichment of video datasets

### Input

#### Metadata Retrieval Strategy (`enableMetadata` flag)

By default, the Actor extracts **transcripts only** for optimal performance and minimal proxy credit consumption.

However, you can enable comprehensive metadata retrieval by setting `enableMetadata: true`:

- **`enableMetadata: false` (default)**: Fast, low-credit mode
  - Extracts: transcript text + video URL
  - Output fields for metadata are present but empty (`None`, `[]`)
  - Recommended for large-scale transcript extraction

- **`enableMetadata: true`**: Full metadata mode
  - Extracts: transcript + video metadata + available subtitles
  - Metadata fields populated: channel name/URL, view count, duration, release date, thumbnail, hashtags
  - Subtitles field includes full list of available subtitle languages
  - Useful for comprehensive video data collection

When `enableMetadata: true`, the Actor emits a single `metadata-enabled` event per run to notify external systems.

##### Example: Enabling metadata

```json
{
  "query": "apify tutorial",
  "limit": 5,
  "langs": ["it", "en"],
  "enableMetadata": true,
  "file_output": "output.json"
}
```

#### Supported input fields

- `direct_url` (array of strings, optional): list of direct YouTube video URLs to process. Supported formats include `youtube.com/watch?v=...`, `youtu.be/...`, and `youtube.com/shorts/...`
- `query` (string, optional): YouTube search query. Optional if `direct_url` is provided
- `range` (array of strings): time filter for YouTube search, one of `hour`, `today`, `this_week`, `this_month`, `this_year`
- `limit` (integer): maximum number of videos to process from search results
- `langs` (array of strings): preferred language order used when selecting transcripts (see table before)
- `file_output` (string): name of the JSON file saved in the key-value store
- `enableMetadata` (boolean, optional): if `true`, fetches video metadata and subtitles; if `false` or omitted, extracts transcript only (default: `false`)

At least one between `query` and `direct_url` must be provided.

#### Supported languages (iso ISO 639-1)

| Codice | Lingua            | Codice | Lingua           | Codice | Lingua         | Codice | Lingua      | Codice | Lingua          | Codice | Lingua     |
| ------ | ----------------- | ------ | ---------------- | ------ | -------------- | ------ | ----------- | ------ | --------------- | ------ | ---------- |
| aa     | Afar              | ab     | Abkhaz           | ae     | Avestan        | af     | Afrikaans   | ak     | Akan            | am     | Amharic    |
| ar     | Arabic            | as     | Assamese         | av     | Avaric         | ay     | Aymara      | az     | Azerbaijani     | ba     | Bashkir    |
| be     | Belarusian        | bg     | Bulgarian        | bi     | Bislama        | bm     | Bambara     | bn     | Bengali         | bo     | Tibetan    |
| br     | Breton            | bs     | Bosnian          | ca     | Catalan        | ce     | Chechen     | ch     | Chamorro        | co     | Corsican   |
| cr     | Cree              | cs     | Czech            | cu     | Church Slavic  | cv     | Chuvash     | cy     | Welsh           | da     | Danish     |
| de     | German            | dv     | Divehi           | dz     | Dzongkha       | ee     | Ewe         | el     | Greek           | en     | English    |
| eo     | Esperanto         | es     | Spanish          | et     | Estonian       | eu     | Basque      | fa     | Persian         | ff     | Fulah      |
| fi     | Finnish           | fj     | Fijian           | fo     | Faroese        | fr     | French      | fy     | Western Frisian | ga     | Irish      |
| gd     | Scottish Gaelic   | gl     | Galician         | gn     | Guarani        | gu     | Gujarati    | gv     | Manx            | ha     | Hausa      |
| he     | Hebrew            | hi     | Hindi            | ho     | Hiri Motu      | hr     | Croatian    | ht     | Haitian         | hu     | Hungarian  |
| hy     | Armenian          | hz     | Herero           | ia     | Interlingua    | id     | Indonesian  | ie     | Interlingue     | ig     | Igbo       |
| ii     | Sichuan Yi        | ik     | Inupiaq          | io     | Ido            | is     | Icelandic   | it     | Italian         | iu     | Inuktitut  |
| ja     | Japanese          | jv     | Javanese         | ka     | Georgian       | kg     | Kongo       | ki     | Kikuyu          | kj     | Kuanyama   |
| kk     | Kazakh            | kl     | Kalaallisut      | km     | Central Khmer  | kn     | Kannada     | ko     | Korean          | kr     | Kanuri     |
| ks     | Kashmiri          | ku     | Kurdish          | kv     | Komi           | kw     | Cornish     | ky     | Kirghiz         | la     | Latin      |
| lb     | Luxembourgish     | lg     | Ganda            | li     | Limburgan      | ln     | Lingala     | lo     | Lao             | lt     | Lithuanian |
| lu     | Luba-Katanga      | lv     | Latvian          | mg     | Malagasy       | mh     | Marshallese | mi     | Maori           | mk     | Macedonian |
| ml     | Malayalam         | mn     | Mongolian        | mr     | Marathi        | ms     | Malay       | mt     | Maltese         | my     | Burmese    |
| na     | Nauru             | nb     | Norwegian Bokmål | nd     | North Ndebele  | ne     | Nepali      | ng     | Ndonga          | nl     | Dutch      |
| nn     | Norwegian Nynorsk | no     | Norwegian        | nr     | South Ndebele  | nv     | Navajo      | ny     | Chichewa        | oc     | Occitan    |
| oj     | Ojibwa            | om     | Oromo            | or     | Oriya          | os     | Ossetian    | pa     | Panjabi         | pi     | Pali       |
| pl     | Polish            | ps     | Pashto           | pt     | Portuguese     | qu     | Quechua     | rm     | Romansh         | rn     | Rundi      |
| ro     | Romanian          | ru     | Russian          | rw     | Kinyarwanda    | sa     | Sanskrit    | sc     | Sardinian       | sd     | Sindhi     |
| se     | Northern Sami     | sg     | Sango            | sh     | Serbo-Croatian | si     | Sinhala     | sk     | Slovak          | sl     | Slovenian  |
| sm     | Samoan            | sn     | Shona            | so     | Somali         | sq     | Albanian    | sr     | Serbian         | ss     | Swati      |
| st     | Southern Sotho    | su     | Sundanese        | sv     | Swedish        | sw     | Swahili     | ta     | Tamil           | te     | Telugu     |
| tg     | Tajik             | th     | Thai             | ti     | Tigrinya       | tk     | Turkmen     | tl     | Tagalog         | tn     | Tswana     |
| to     | Tonga             | tr     | Turkish          | ts     | Tsonga         | tt     | Tatar       | tw     | Twi             | ty     | Tahitian   |
| ug     | Uighur            | uk     | Ukrainian        | ur     | Urdu           | uz     | Uzbek       | ve     | Venda           | vi     | Vietnamese |
| vo     | Volapük           | wa     | Walloon          | wo     | Wolof          | xh     | Xhosa       | yi     | Yiddish         | yo     | Yoruba     |
| za     | Zhuang            | zh     | Chinese          | zu     | Zulu           |        |             |        |                 |        |            |

#### Example input with direct URLs only

```json
{
  "direct_url": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/9bZkp7q19f0"
  ],
  "langs": ["it", "en"],
  "file_output": "output.json"
}
```

#### Example input with query and direct URLs

```json
{
  "direct_url": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "query": "apify tutorial",
  "range": ["this_week"],
  "limit": 5,
  "langs": ["it", "en"],
  "file_output": "output.json"
}
```

#### Example input with direct URLs only and enableMetadata = true

```json
{
  "direct_url": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/9bZkp7q19f0"
  ],
  "langs": ["it", "en"],
  "enableMetadata": true,
  "file_output": "output.json"
}
```

#### Example input with query and direct URLs and enableMetadata = true

```json
{
  "direct_url": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "query": "apify tutorial",
  "range": ["this_week"],
  "limit": 5,
  "langs": ["it", "en"],
  "enableMetadata": true,
  "file_output": "output.json"
}
```

When both `direct_url` and `query` are provided, all videos listed in `direct_url` are processed and added to the output together with the search results. When `enableMetadata` is set to `true`, the Actor will fetch comprehensive metadata and available subtitles for each video and emit an `apify-actor-metadata` event upon completion.

### Output

Each dataset item contains structured YouTube transcript and metadata fields like these:

```json
{
  "id": "video_id",
  "title": "Video title",
  "url": "https://www.youtube.com/watch?v=video_id",
  "autor": "Channel name",
  "text": "[00:00] transcript text...",
  "channel_name": "Channel name",
  "channel_url": "https://www.youtube.com/@channel",
  "video_title": "Detailed video title",
  "video_url": "https://www.youtube.com/watch?v=video_id",
  "views_count": 123456,
  "duration_seconds": 542,
  "release_date": "2026-04-13",
  "thumbnail_url": "https://i.ytimg.com/vi/video_id/maxresdefault.jpg",
  "hashtags": ["apify", "youtube", "scraping"],
  "like_count": 5432,
  "comment_count": 123,
  "description": "Full video description text here...",
  "keywords": ["youtube", "scraping", "api"],
  "categories": ["Education", "Technology"],
  "is_live": false,
  "availability": "unlisted",
  "language": "en",
  "chapters": [
    {
      "title": "Introduction",
      "start_time": 0
    }
  ],
  "series": null,
  "season": null,
  "episode": null,
  "subtitles": [
    {
      "language_code": "en",
      "language": "English",
      "is_generated": true,
      "is_translatable": true
    }
  ]
}
```

The Actor also saves the complete output array into the APIFY key-value store using the file name specified in `file_output`.

### How the YouTube transcript extraction works

The Actor follows this strategy:

1. If `direct_url` is provided, process each direct YouTube URL and extract transcript and metadata.
2. If `query` is provided, search YouTube videos using the selected time filter.
3. For each video, try to find a manually created transcript in the languages you requested.
4. If no manual transcript is available, try an auto-generated transcript.
5. If no requested language is available, fall back to the first available transcript.
6. Save transcript text and structured metadata in the output dataset.

This makes the Actor practical for multilingual transcript scraping, targeted video extraction, and broad topic monitoring.

### Who is this Actor for?

This Actor is a good fit for:

- SEO specialists
- marketers
- data engineers
- content analysts
- AI data learning teams
- researchers
- agencies monitoring YouTube niches
- users who need transcripts from specific YouTube links

### Limitations

The actor has the following limitations:

- **Public videos only**: Private or restricted videos are not supported.
- **Transcripts required**: The Actor can only extract data from videos that have transcripts enabled.
- **Age-gated videos not supported**: Videos marked as age-restricted (18+, 14+, etc.) cannot be accessed without YouTube account authentication. The Actor will return empty metadata and transcript for age-gated videos because YouTube blocks unauthenticated access to these videos for protection purposes.

To work with age-gated videos, you would need to implement YouTube account authentication, which is not currently supported by this Actor.

### Summary

If you need a YouTube transcript scraper for APIFY that extracts subtitles, transcript text, hashtags, thumbnails, views, duration, and release date from either search results or direct video URLs, this Actor gives you a clean starting point with structured JSON output and proxy support.

# Actor input Schema

## `direct_url` (type: `array`):

List of direct YouTube URLs to download the transcript from. Each URL can be in the format youtube.com/watch?v=..., youtu.be/..., or youtube.com/shorts/.... The specified videos are always added to the output, regardless of the query.

## `query` (type: `string`):

YouTube search query. Optional if direct\_url is specified.

## `range` (type: `array`):

Time filter to apply to YouTube searches. If multiple values ​​are provided, the first one will be used.

## `limit` (type: `integer`):

Maximum number of videos to analyze via search query

## `langs` (type: `array`):

Preferred languages ​​to retrieve the first available transcript.

## `file_output` (type: `string`):

Name of the JSON file to save to the key-value store.

## `enableMetadata` (type: `boolean`):

If true, also fetches video metadata and available subtitles. If false or omitted, actor behaves as before.

## Actor input object example

```json
{
  "direct_url": [
    "https://www.youtube.com/watch?v=XqsDoIjXDPk"
  ],
  "limit": 10,
  "langs": [
    "it",
    "en"
  ],
  "file_output": "output.json",
  "enableMetadata": false
}
```

# Actor output Schema

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

No description

# 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 = {
    "direct_url": [
        "https://www.youtube.com/watch?v=XqsDoIjXDPk"
    ],
    "langs": [
        "it",
        "en"
    ],
    "file_output": "output.json"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ilborso/youtube-text-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 = {
    "direct_url": ["https://www.youtube.com/watch?v=XqsDoIjXDPk"],
    "langs": [
        "it",
        "en",
    ],
    "file_output": "output.json",
}

# Run the Actor and wait for it to finish
run = client.actor("ilborso/youtube-text-scraper").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 '{
  "direct_url": [
    "https://www.youtube.com/watch?v=XqsDoIjXDPk"
  ],
  "langs": [
    "it",
    "en"
  ],
  "file_output": "output.json"
}' |
apify call ilborso/youtube-text-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/ziYv81xR6O1r8CdD4/builds/SkM5dYBbqYgG3xrZi/openapi.json
