# YouTube Scraper: Videos, Transcripts & Comments | from $1.80/1K (`bovi/youtube-scraper`) Actor

Scrape YouTube videos, search results, channel uploads, full transcripts, and comments. No API key needed. Returns views, description, tags, thumbnails, and full transcript text. parse\_confidence in every record catches silent API drift.

- **URL**: https://apify.com/bovi/youtube-scraper.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.75 / 1,000 video-results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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 Scraper — Video Metadata, Transcripts & Comments

Extract YouTube video data at scale without an API key or quota limits. This YouTube scraper covers video metadata, keyword search results, channel upload feeds, full video transcripts (including auto-generated captions), and top comments — all in one actor with pay-per-result pricing.

Whether you need to monitor a competitor's channel, feed transcripts into an LLM pipeline, or track video engagement across a topic, this scraper gives you clean structured data with a `parse_confidence` quality score on every record.

### Why use this YouTube scraper instead of the YouTube Data API?

The official YouTube Data API v3 has a daily quota of 10,000 units. A single search call costs 100 units — that's **100 searches per day** on the free tier. This actor calls YouTube's internal InnerTube API and parses `ytInitialData` / `ytInitialPlayerResponse` directly, with no quota cap and no API key setup.

### What you get — 5 scrape modes

- **`video_details`** — Full metadata for one or more YouTube videos
- **`search`** — Keyword search results with ranking position
- **`channel_videos`** — All recent uploads from a YouTube channel
- **`transcript`** — Full transcript text with timestamps (auto-generated + manual captions)
- **`comments`** — Top comments for a video

### Features

- **5 modes**: `video_details`, `search`, `channel_videos`, `transcript`, `comments`
- **No API key**: Uses YouTube's internal InnerTube API and HTML parsing
- **Transcripts**: Full text with timestamps via `youtube-transcript-api` (handles auto-generated captions)
- **parse_confidence**: Every record includes a quality score (0.0–1.0) — Apify's daily canary catches silent failures
- **PPE pricing**: Pay only for results scraped (`video-result` event per record)

### Modes

#### `video_details`
Full metadata for one or more YouTube videos.

**Input**: `videoUrls` — list of YouTube URLs or bare video IDs.

**Output fields**: `video_id`, `title`, `channel`, `channel_id`, `views`, `published`, `duration_seconds`, `duration_raw`, `description`, `tags`, `thumbnail`, `thumbnails`, `video_url`

#### `search`
Search YouTube by keyword and return video results.

**Input**: `searchQueries` — list of search terms.

**Output**: Same schema as `video_details` plus relative `published` (e.g. "3 weeks ago").

#### `channel_videos`
List recent uploads from a YouTube channel.

**Input**: `channels` — handles (`@freeCodeCamp`), channel IDs (`UCxxx`), or full URLs.

**Output**: `video_id`, `title`, `views`, `published` (relative), `duration_raw`, `thumbnail`

#### `transcript`
Extract full transcript text from a video.

**Input**: `videoUrls`, optional `transcriptLanguage` (default: `en`).

**Output**: `transcript_text` (full joined text), `language`, `is_generated`, `segment_count`

Note: Falls back to auto-generated captions in any language if the requested language is unavailable.

#### `comments`
Fetch top comments for a video.

**Input**: `videoUrls`, optional `maxComments` (default: 20).

**Output**: `comment_id`, `author`, `text`, `likes`, `is_pinned`

### Proxy

YouTube tolerates datacenter IPs for metadata scraping. Use Apify Proxy (residential) at high volume or if you encounter blocks. Leave `proxyConfiguration` empty for no proxy.

### parse_confidence

Every record includes a `parse_confidence` field (1.0 = all expected fields present, 0.0 = critical failure). If YouTube changes its HTML structure, confidence drops — giving you a machine-readable drift signal before buyers notice.

### Pricing

PPE event: `video-result` — one charge per record pushed.

### Technical notes

- Video metadata: parse `ytInitialPlayerResponse` from watch-page HTML (no API key needed)
- Search: InnerTube `POST /youtubei/v1/search` with WEB client context
- Channel videos: parse `ytInitialData` `lockupViewModel` from channel page HTML
- Transcripts: `youtube-transcript-api` library (handles PoToken internally)
- Comments: InnerTube `POST /youtubei/v1/next` + `frameworkUpdates.entityBatchUpdate` entity store

### Frequently asked questions

#### Does this YouTube scraper work without an API key?

Yes. The actor uses YouTube's internal InnerTube API and HTML parsing — no API key, no Google Cloud project, no quota limits to manage.

#### Can I scrape YouTube transcripts for multiple videos at once?

Yes. Pass a list of video URLs or video IDs to `videoUrls`. Each video generates one `transcript` record with the full joined text, language code, and whether it's auto-generated.

#### What happens if a video has no transcript?

The actor sets `parse_confidence` below 1.0 and includes a `warnings` entry. Your downstream pipeline can filter on `parse_confidence` rather than crashing on missing fields.

#### Is proxy needed?

YouTube tolerates datacenter IPs for most scraping. Leave `proxyConfiguration` empty for no proxy. At high volume or if you hit CAPTCHAs, switch to Apify RESIDENTIAL proxy.

#### How is pricing calculated?

This actor uses **pay-per-result** (PPE). One charge (`video-result` event) per record pushed to the dataset. Failed lookups, retries, and probe requests are not charged.

---

*Not affiliated with YouTube or Google.*

### Integrations

Built for content researchers, competitive analysts, and LLM-pipeline builders extracting video metadata, transcripts, and comments at scale — the JSON/dataset output drops into the tools you already run, no glue code:

- **n8n / Make / Zapier** — trigger a run or pipe every new dataset item into 500+ apps (Google Sheets, Airtable, Slack, HubSpot, your database) with no code: [n8n](https://docs.apify.com/platform/integrations/n8n), [Make](https://docs.apify.com/platform/integrations/make), [Zapier](https://docs.apify.com/platform/integrations/zapier).
- **Webhooks** — fire your own endpoint the moment a run finishes, to push results straight into your pipeline ([docs](https://docs.apify.com/platform/integrations/webhooks)).
- **MCP server** — expose this actor as a tool to Claude, Cursor, or any [MCP client](https://mcp.apify.com) so an AI agent can pull this data mid-conversation ([guide](https://blog.apify.com/how-to-use-mcp/)).
- **API & SDKs** — fetch the dataset as JSON, CSV, or Excel through the Apify REST API or the Python / JS SDKs.

See all [Apify integrations](https://apify.com/integrations).

# Actor input Schema

## `mode` (type: `string`):

Scraping mode. video_details: fetch full metadata for specific videos. search: find videos by keyword. channel_videos: list recent uploads from a channel. transcript: extract full transcript text from a video. comments: fetch top comments for a video.
## `videoUrls` (type: `array`):

YouTube video URLs or bare video IDs. Used for video_details, transcript, and comments modes. Example: ['https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'rfscVS0vtbw'].
## `searchQueries` (type: `array`):

Keywords to search on YouTube. Used for search mode. Each query returns up to maxResults videos. Example: ['python tutorial', 'machine learning basics'].
## `channels` (type: `array`):

YouTube channels to scrape recent videos from. Used for channel_videos mode. Accepts: @handle (@freeCodeCamp), channel ID (UCVHhXGFkrGHdAnJesTbfmXg), or full channel URL. Example: ['@freeCodeCamp', 'UCVHhXGFkrGHdAnJesTbfmXg'].
## `maxResults` (type: `integer`):

Maximum items to return per query or channel. For search mode: max videos per query. For channel_videos: max videos per channel. For comments: same as maxComments. Default: 20.
## `transcriptLanguage` (type: `string`):

Preferred language code for transcripts (e.g. 'en', 'es', 'de'). Falls back to auto-generated captions in any language if the requested language is unavailable.
## `maxComments` (type: `integer`):

Maximum number of top comments to fetch per video in comments mode. Default: 20.
## `proxyConfiguration` (type: `object`):

Optional Apify Proxy configuration. YouTube tolerates datacenter IPs for metadata scraping. Use residential proxies at scale or if you encounter blocks. Leave empty to run without proxy.

## Actor input object example

```json
{
  "mode": "video_details",
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxResults": 20,
  "transcriptLanguage": "en",
  "maxComments": 20
}
````

# Actor output Schema

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

Dataset containing Youtube Scraper records (title, channel, views, duration\_raw, published, author, mode, video\_id, parse\_confidence, video\_url, scraped\_at).

# 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 = {
    "mode": "video_details",
    "videoUrls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "maxResults": 20,
    "transcriptLanguage": "en",
    "maxComments": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/youtube-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 = {
    "mode": "video_details",
    "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "maxResults": 20,
    "transcriptLanguage": "en",
    "maxComments": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/youtube-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 '{
  "mode": "video_details",
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxResults": 20,
  "transcriptLanguage": "en",
  "maxComments": 20
}' |
apify call bovi/youtube-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Scraper: Videos, Transcripts & Comments | from $1.80/1K",
        "description": "Scrape YouTube videos, search results, channel uploads, full transcripts, and comments. No API key needed. Returns views, description, tags, thumbnails, and full transcript text. parse_confidence in every record catches silent API drift.",
        "version": "0.1",
        "x-build-id": "rj2YBF8wS7zfs7gTZ"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/bovi~youtube-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-bovi-youtube-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/bovi~youtube-scraper/runs": {
            "post": {
                "operationId": "runs-sync-bovi-youtube-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/bovi~youtube-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-bovi-youtube-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "video_details",
                            "search",
                            "channel_videos",
                            "transcript",
                            "comments"
                        ],
                        "type": "string",
                        "description": "Scraping mode. video_details: fetch full metadata for specific videos. search: find videos by keyword. channel_videos: list recent uploads from a channel. transcript: extract full transcript text from a video. comments: fetch top comments for a video.",
                        "default": "video_details"
                    },
                    "videoUrls": {
                        "title": "Video URLs or IDs",
                        "type": "array",
                        "description": "YouTube video URLs or bare video IDs. Used for video_details, transcript, and comments modes. Example: ['https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'rfscVS0vtbw'].",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchQueries": {
                        "title": "Search Queries",
                        "type": "array",
                        "description": "Keywords to search on YouTube. Used for search mode. Each query returns up to maxResults videos. Example: ['python tutorial', 'machine learning basics'].",
                        "items": {
                            "type": "string"
                        }
                    },
                    "channels": {
                        "title": "Channels",
                        "type": "array",
                        "description": "YouTube channels to scrape recent videos from. Used for channel_videos mode. Accepts: @handle (@freeCodeCamp), channel ID (UCVHhXGFkrGHdAnJesTbfmXg), or full channel URL. Example: ['@freeCodeCamp', 'UCVHhXGFkrGHdAnJesTbfmXg'].",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum items to return per query or channel. For search mode: max videos per query. For channel_videos: max videos per channel. For comments: same as maxComments. Default: 20.",
                        "default": 20
                    },
                    "transcriptLanguage": {
                        "title": "Transcript Language",
                        "type": "string",
                        "description": "Preferred language code for transcripts (e.g. 'en', 'es', 'de'). Falls back to auto-generated captions in any language if the requested language is unavailable.",
                        "default": "en"
                    },
                    "maxComments": {
                        "title": "Max Comments",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Maximum number of top comments to fetch per video in comments mode. Default: 20.",
                        "default": 20
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Optional Apify Proxy configuration. YouTube tolerates datacenter IPs for metadata scraping. Use residential proxies at scale or if you encounter blocks. Leave empty to run without proxy."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
