# YouTube Transcript Scraper — human vs auto (`rankfabrik/youtube-transcript-scraper`) Actor

Give it YouTube video URLs or a search term to get the full transcript text and the language code actually used, on essentially every captioned video, with a plain true/false flag telling you whether each transcript was written by a human or auto-generated.

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

## Pricing

from $2.00 / 1,000 auto-generated transcripts

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/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 — full text, language and a human-vs-auto flag on every row

Give it video URLs or a search term, and it returns the full transcript text
plus the language code of the track actually used, on essentially every video
that has captions at all.

Every row also tells you, with a plain `true`/`false`, whether that transcript
was **written by a human** or **generated by speech-to-text**, and the accuracy
gap between the two is not small. Almost no transcript API surfaces which one
you got. This one flags it on every single row and reports the human-vs-auto
split for the whole batch **before** you spend your budget, so you know the
quality of what you are buying up front.

> **Unofficial tool — not affiliated.** This is an independent tool. It is not
> affiliated with, endorsed by, or sponsored by YouTube, Google, or any other
> third-party service. All product names, logos and brands are the property of
> their respective owners and are used for identification only.

***

### Source and legality

This reads the caption track that the source's own mobile-app clients receive
from the public player: no account is ever created, no session, no paywalled
content, and no anti-bot protection bypassed. It accesses only what is already
public. Timestamped verbatim segments, plus SRT and VTT export, are live in
production **today**, not on a roadmap.

> **Copyright.** A transcript may reproduce content that is protected by
> copyright. This tool does not grant you any right or license over that
> content. You are responsible for ensuring that your use of any transcript
> (fair use, licensing, or private study, as the case may be) is lawful.

### You see the quality mix before you pay, not after

Most transcript APIs work in the dark: you pay, you run, and only then learn
how many videos actually had usable captions, and of what kind. This one shows
you the `human` percentage — the share of rows with a human-written track — in
two places: the run's status message while it works, and a `batchCompleteness`
block on every single row. A video with no caption track, or a live stream, is
still returned as a row so you know exactly why — but it is **never billed**.
See *Pricing*.

***

### What you get

One row per video:

| Field | Notes |
|---|---|
| `id` | 11-character YouTube video ID |
| `title`, `channel`, `channelId` | video and channel metadata |
| `durationSeconds`, `views` | duration, view count |
| `description`, `keywords` | video description and tags |
| `isLive` | `true` if the video is a live stream |
| `thumbnail` | thumbnail URL |
| `language` | language code of the caption track actually used |
| `auto` / `human` | `true` when the track is speech-to-text, `false`/`true` when a person wrote it — **the core disclosure of this product** |
| `availableLanguages` | every language code the video has a track for, not just the one chosen |
| `text` | full transcript, plain text |
| `totalWords`, `characters` | word and character counts |
| `segments` | timestamped sentence-by-sentence breakdown (`start`, `duration`, `text`), when requested |
| `chapters` | each chapter with its title, start time, and **the text actually spoken during it** — not just the chapter title, when requested |
| `batchCompleteness` | the completeness percentages of this run, including `human` (% of rows with a human-written track) |

**No field is ever inferred.** A video with no captions is reported as
unavailable and not billed — you never receive a transcript hallucinated from
the title and description to fill the gap.

The `batchCompleteness` percentages mirror exactly what YouTube publishes for
the videos you asked about, not what we drop. A low `human` reading simply
means most of those videos only had a machine-generated track available — not
that a human transcript was discarded. And because you read it before you pay,
the quality mix is never a surprise you discover after the run.

***

### Example output — one row, illustrative

```json
{
  "id": "jNQXAC9IVRw",
  "title": "Example video title, as published",
  "channel": "Example Channel",
  "channelId": "UCExampleChannelId",
  "durationSeconds": 245,
  "views": 128394,
  "description": "Video description, as published.",
  "keywords": ["example", "keyword"],
  "isLive": false,
  "thumbnail": "https://i.ytimg.com/vi/jNQXAC9IVRw/hqdefault.jpg",
  "language": "en",
  "auto": false,
  "human": true,
  "availableLanguages": ["en", "fr"],
  "text": "Full transcript text goes here...",
  "totalWords": 512,
  "characters": 2890,
  "segments": [
    { "start": 0, "duration": 4.2, "text": "Example opening line of the transcript." }
  ],
  "batchCompleteness": {
    "text": 100,
    "language": 100,
    "channel": 98,
    "durationSeconds": 100,
    "views": 97,
    "thumbnail": 100,
    "human": 34
  }
}
```

`human: true` here means a person wrote this particular track — the core
disclosure of this product. `batchCompleteness.human` is the same object on
every row of the run: read it once and you know what share of the whole
batch is human-written versus machine-generated.

***

### Good to know before you run it

Published up front, not buried in a changelog — so there are no surprises.

- **Auto-generated captions can be inaccurate**, especially on accented speech,
  technical vocabulary or overlapping speakers. `auto` /
  `human` tells you which you got on every row, so you can filter or
  re-weight downstream instead of finding out the hard way.
- **Language preference wins over caption quality.** If you ask for French and
  the video only has an auto-generated French track plus a professionally
  translated English one, you get the auto-generated French track, matching
  what a French-speaking viewer actually sees. Set `languages` to `en` if you'd
  rather have the higher-quality translation.
- **Chapters cost one extra request per video** and are off by default. When
  on, chapter text is derived by slicing the transcript at the source's own
  chapter timestamps — it is not a separately authored chapter summary.
- **Live streams and videos without any caption track are not billed.** They
  are still returned as a row (`available: false`, with a reason) so you know
  why, but you pay nothing for them.
- **Search mode (`searchTerm`) has a soft ceiling.** Beyond a handful of result
  pages the source mostly re-serves what it already returned. Measured yield on
  six pages: +20, +10, +1, +6, +2. Set expectations accordingly for very broad
  terms.

***

### Input

| Field | Required | Default | Meaning |
|---|---|---|---|
| `videos` | one of the two | — | one YouTube URL or video ID per line |
| `searchTerm` | one of the two | — | search by keyword instead of listing videos |
| `searchLimit` | no | 10 | max videos pulled from `searchTerm` |
| `languages` | no | `en` | preferred caption languages, in order |
| `includeSegments` | no | `true` | include the timestamped sentence breakdown |
| `includeChapters` | no | `false` | include chapters with spoken text per chapter |
| `maxResults` | no | 25 | hard ceiling on videos processed (and billed) across both sources |

Example:

```json
{
  "videos": "https://www.youtube.com/watch?v=dQw4w9WgXcQ\nhttps://youtu.be/9bZkp7q19f0",
  "languages": "en",
  "includeChapters": true,
  "maxResults": 20
}
```

***

### Pricing

Pay per result, in two tiers, because a human-written transcript is worth more
than an auto-generated one:

| Event | Price | What it is |
|---|---|---|
| `transcript-human` | $4.00 per 1,000 rows | a video with a human-written caption track |
| `transcript-auto` | $2.00 per 1,000 rows | a video with a speech-to-text caption track |

You are charged per row written to your dataset, and for nothing else. Videos
with no usable caption track, live streams, and refused requests cost you
zero. Your own spending cap is enforced by the platform — the run stops
cleanly when it is reached, mid-dataset, without burning compute you did not
authorise.

***

### Prefer a hosted API with a flat monthly plan?

This actor bills per result on the Apify platform. If you'd rather call a
hosted endpoint with your own key, a flat monthly quota, and the same
human-vs-auto disclosure on every response, the same data ships as a
standalone API:

- **YouTube Transcript API** — the same caption-track transparency, on a flat
  monthly plan: <https://rankfabrik.com/captions-api-pricing>
- Sibling APIs on the same principle:
  [Places](https://rankfabrik.com/google-places-api-pricing) (local business
  data, one flat unit per enriched record) and
  [Jobs](https://rankfabrik.com/jobs-api-pricing) (built for volume past the
  1,000-result-per-query wall).

The engine behind both is the same, and both report the same measured fill
rate. Choose the billing model that suits you.

***

### Legal & responsible use

**Your responsibility as the user.** You are solely responsible for how you use
the transcripts this tool returns, including compliance with applicable laws,
the source's terms, and third-party copyright (see the copyright note above). We
provide a data-access tool and grant no license over any video's content.

**Removal requests.** Rights holders who want a specific record removed can
contact contact@rankfabrik.com. Justified requests are processed promptly
(target: within 30 days).

***

### Support

Something look off in a run, or a question about a field? The actor's **Issues**
tab is the place, and quoting the run helps: its completeness figures are
logged, so we read the same numbers you did instead of trading guesses.

# Actor input Schema

## `videos` (type: `string`):

One YouTube URL or video ID (11 characters) per line. Accepted forms: full link, short youtu.be link, /shorts/ link, or raw ID. Leave empty to use only the "Search" field below.

## `searchTerm` (type: `string`):

Optional. Finds videos by keyword and transcribes them all, on top of those listed in "Videos to transcribe". Handy to cover a topic without collecting the links by hand first.

## `searchLimit` (type: `integer`):

Applies only to the "Search" field. Yield drops off quickly past a handful of pages — the source mostly re-serves what it already returned.

## `languages` (type: `string`):

Language codes separated by commas, in order of preference: "en,fr" tries English first, then French. An auto-generated track in the requested language is preferred over a human translation in another language.

## `includeSegments` (type: `boolean`):

Adds the sentence-by-sentence breakdown with timestamps (start, duration, text), on top of the full text. Turn off to keep the plain text only when the breakdown isn't needed.

## `includeChapters` (type: `boolean`):

Adds the video's chapters with, for each, the text actually spoken during it — not just its title. Costs one extra request per video (50–90 KB versus 5 KB for the player alone).

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

Hard ceiling, across both sources (list + search), on the number of videos processed — and therefore billed at most.

## Actor input object example

```json
{
  "videos": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "searchLimit": 10,
  "languages": "en",
  "includeSegments": true,
  "includeChapters": false,
  "maxResults": 25
}
```

# Actor output Schema

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

All transcript rows written to the default dataset.

# 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 = {
    "videos": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "languages": "en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("rankfabrik/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 = {
    "videos": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "languages": "en",
}

# Run the Actor and wait for it to finish
run = client.actor("rankfabrik/youtube-transcript-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 '{
  "videos": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "languages": "en"
}' |
apify call rankfabrik/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rankfabrik/youtube-transcript-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/lNlHdUjvTdUrsZNEK/builds/Wk2gQKzs6KW7hr3hq/openapi.json
