# YouTube Video Summarizer - Summary, Key Points & Timestamps (`s-r/youtube-summarizer`) Actor

YouTube video summarizer: turn any link into a summary you can read — the gist in the style you choose, the key points, and a link that opens the video at the second each point is made. For researchers, students and teams who need to know what a video says without watching it.

- **URL**: https://apify.com/s-r/youtube-summarizer.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Videos, AI
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 per-run start fees

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Video Summarizer — Summary, Key Points and Timestamps

YouTube video summarizer for any link: paste a video URL and get back a summary
in the style you choose, the key points, and a timestamped link to the moment
each point is made. Built for researchers, students, editors and analysts who
need to know what a video says before they give it an hour of their day.

A full link, a `youtu.be` link, a Shorts link or a bare video id all work.

### Why not just read the transcript

Because a transcript is not a summary. An hour of speech is thousands of words
of false starts, filler and "so basically", and nobody reads that to find out
whether the video was worth watching. Transcript downloaders hand you all of
it. This hands you the answer, plus the exact seconds the answer came from.

### Four styles, for four different jobs

- **Brief** — three or four sentences. For triage: is this video worth my time?
- **Detailed** — four short paragraphs covering the argument, the evidence and
  the conclusion. For when you are not going to watch it and need to know what
  it said.
- **Bullet points** — six to ten complete sentences, one claim each. The best
  one to paste into notes.
- **Chapters** — the video broken into its natural sections. For long talks and
  interviews.

### Timestamps are matched, not invented

This is the part worth understanding, because it is where these tools usually
quietly lie.

A model asked to produce timestamps will produce convincing ones that are not
in the video. So no timestamp here comes from the model. The key points it
writes are matched back against the transcript's own segments, and the
timestamp you get is the start of the segment those words actually came from.

A point that cannot be matched to a segment gets **no timestamp** rather than a
guess. One shared word does not count as a match, because "video" appearing in
both is a coincidence, not a location. Each matched point also carries a `url`
that opens the video at that second, so a reviewer can check the claim in one
click.

### Long videos are summarised in full

A transcript too long for one pass is split, each piece is summarised, and
those summaries are summarised again. `transcript_chunks` tells you how many
passes it took.

The alternative, which is what a single call does when overfed, is to silently
drop the end. On a two-hour talk that means the conclusion is missing and
nothing in the output says so.

### Videos without captions

A large share of YouTube has no captions at all. Those come back with
`summarised: false` and an error saying so, and they are **not charged** — the
per-video price only applies to videos that produced a summary.

**Prefer human captions** is on by default. Auto-generated captions mishear
names, numbers and technical terms, and those mistakes then get repeated in the
summary as if they were facts. When a human-written track exists it is used.

### Summary language

**Summary language** writes the summary in whatever language you name,
regardless of what the video is in. Leave it empty to follow the transcript.
This is separate from **Transcript languages**, which chooses which caption
track to read. A Dutch summary of an English lecture is one field away.

### Input

The form on the Store page is the whole input; the same fields work as JSON
when you call the Actor through the Apify API.

| Field | Type | Default | Description |
|---|---|---|---|
| `videoUrls` | array | **required** | One video per entry. A full link, a `youtu.be` link, a Shorts link or a bare 11-character id. |
| `summaryStyle` | string | `brief` | `brief`, `detailed`, `bullets` or `chapters`. |
| `outputLanguage` | string | empty | Write the summary in this language whatever the video is in. Empty follows the transcript. |
| `preferred_languages` | array | empty | Caption languages to prefer, best first. Falls back to English, then the first track available. |
| `prefer_manual` | boolean | `true` | Use human-written captions over auto-generated ones when both exist. |
| `includeTranscript` | boolean | `false` | Add the raw transcript to each row. Off by default: it is the bulk of the payload and the summary is the point. |
| `model` | string | empty | Leave empty for the default. Only set it if you know which model you want. |
| `concurrency` | integer | `3` | How many transcripts to fetch at once, from 1 to 10. |

### Output of the YouTube video summarizer

One dataset row per video, in input order, with the run counters in the
key-value store under `summary` and run-level errors under `errors`.

| Field | What it holds |
|---|---|
| `video_id`, `video_url` | The video the row belongs to, as a canonical watch link. |
| `language`, `is_generated` | Which caption track was read, and whether a person wrote it. |
| `duration_seconds`, `word_count` | Length of the video and size of the transcript behind the summary. |
| `summary`, `summary_style` | The summary itself, and the style that produced it. |
| `key_points`, `key_point_count` | Main points, each with `point`, `seconds`, `timestamp` and a `url` that opens at that second. |
| `transcript_chunks` | How many passes the transcript was summarised in — more than one means a long video. |
| `transcript` | The raw transcript, present only when you asked for it. |
| `summarised`, `error` | Whether a summary was produced, and if not, why. |
| `chapters` | Kept from earlier versions of this Actor so existing pipelines do not break; always `null`. |
| `position` | Place of the row in the run: a 1-based integer, in input order. |

A real row, trimmed only by dropping the middle eleven of the thirteen key
points (first and last kept), from a 18-minute lecture with 3,357 transcript
words:

```json
{
  "video_id": "aircAruvnKk",
  "video_url": "https://www.youtube.com/watch?v=aircAruvnKk",
  "language": "en",
  "is_generated": false,
  "duration_seconds": 1105.64,
  "word_count": 3357,
  "summary_style": "brief",
  "summary": "This video explains the basic structure of a \"plain vanilla\" neural network designed to recognize handwritten digits. It describes how a network uses layers of neurons—consisting of an input layer for pixels, hidden layers for detecting edges and patterns, and an output layer for digit classification—to process information. The author concludes that the network functions as a complex mathematical function where weights and biases act as \"knobs and dials\" that can be tuned to recognize specific patterns.",
  "key_points": [
    {"point": "Neural networks are inspired by the brain and can be used to recognize handwritten digits.",
     "seconds": 163.38, "timestamp": "2:43",
     "url": "https://www.youtube.com/watch?v=aircAruvnKk&t=163s"},
    {"point": "Modern networks often use ReLU (Rectified Linear Unit) instead of sigmoid functions because it is easier to train.",
     "seconds": 1059.4, "timestamp": "17:39",
     "url": "https://www.youtube.com/watch?v=aircAruvnKk&t=1059s"}
  ],
  "chapters": null,
  "position": 1,
  "key_point_count": 13,
  "transcript_chunks": 1,
  "summarised": true,
  "error": null
}
```

The matching run summary in the key-value store reads
`{"videos": 1, "summarised": 1, "withoutTranscript": 0, "totalWords": 3357,
"withTimestamps": 1, "style": "brief", "fetchedInSeconds": 6.83, "errorCount": 0}`.

A video with captions switched off comes back as a row with
`summarised: false` and `error` explaining it, and the run still succeeds — a
failed video is data, not a crashed job. A run whose links are all blank
produces no rows and succeeds as well.

### Use cases

- **Deciding what to watch.** Run a week of subscribed videos through
  *brief* and keep the four that earned an hour.
- **Literature and interviews.** Pull `key_points` with their timestamps, then
  open only the cited seconds. The claim and its location arrive together.
- **Meeting and lecture notes.** *Bullet points* pastes straight into a doc,
  and `outputLanguage` writes it in the language your team works in.
- **Feeding a model.** One row per video gives a clean, structured context
  block — summary, points, timestamps, and the transcript only when you turn
  `includeTranscript` on.
- **Batch triage.** List dozens of links, watch `transcript_chunks` and
  `key_point_count` to see which videos were long enough to be worth a second
  pass.

### How it compares

- **Transcript downloaders** (including our own free YouTube transcript
  Actor) give you the raw text: accurate, complete, unread. This gives you the
  answer and the seconds it came from.
- **Browser extensions and one-off web tools** such as NoteGPT, MindGrasp,
  Decopy and Noiz summarize the video you are looking at, in a tab, by hand.
  Useful once; they do not take a list of fifty links, return JSON you can join
  on, or tell you which caption track was used.
- **Asking a chat model for a summary** is the "youtube summary with chatgpt"
  route: you paste the transcript yourself, you hit the context limit on long
  videos, and you get timestamps the model invented. Here the transcript is
  fetched for you, long ones are split, and every timestamp is matched against
  the transcript's own segments.
- **Generic AI summarizers** summarise text you hand them. This one reads
  YouTube's captions, prefers human-written tracks, and refuses to invent a
  second that is not in the video.

### FAQ

#### Does it work on videos without subtitles?

No, and it says so instead of guessing. A video with captions disabled comes
back with `summarised: false` and an error naming the video, the run succeeds,
and you are not charged for that video. Check whether your videos have captions
before you promise a colleague a summary.

#### Can I summarize a whole playlist or a channel?

You can paste as many links as you like — one video per line, up to the limit
your plan allows. The Actor reads captions, so a playlist becomes one row per
video, in the order you pasted them. Building the link list is a job for a
search or channel scraper; this Actor does the reading.

#### Are the timestamps reliable?

They are matched, not generated. Each key point is compared against the
transcript's own timed segments, and the timestamp is the start of the segment
the words came from. A point with no good match gets no timestamp at all
rather than a plausible-looking wrong one. Every point also carries a `url`
that opens the video at that second, so verification is one click.

#### Which summary style should I use?

*Brief* for triage, *detailed* when you will not watch the video at all,
*bullets* for notes you will paste somewhere, *chapters* for talks and
interviews where the structure is the point. The style is a field, so you can
run the same links twice and keep both.

#### Can I get the summary in another language?

Yes. **Summary language** writes the summary in the language you name
regardless of what the video is in, while **Transcript languages** picks which
caption track to read. Summary in Spanish from an English lecture is one field.

#### How do I run it without code?

The input form on this page is the whole input: paste links, pick a style, hit
Run. For anything repeatable, schedule the Actor or call it through the Apify
API with the same JSON fields listed under **Input**.

### Pricing

Pay per event, no subscription and no minimum. Two events make up the bill:

- **Per-run start fee** — charged once per run, $0.002, whether the run
  returns one row or fifty.
- **Video summary** — $0.02 per video actually summarised. Videos that came
  back without captions are not charged, and neither is anything you did not
  get.

A run over ten videos therefore costs $0.002 plus ten times $0.02, and a run
that finds nothing costs the start fee alone. Users on a free Apify plan are
delivered at most ten videos per run; paying users get the whole list.
Prices are the ones on the Store page at the time of writing.

### Errors

| Code | Meaning |
|---|---|
| `transcript_failed` | The transcript could not be fetched |
| `summary_failed` | The transcript was fetched but the summary could not be written |
| `bad_input` | No video URL was given |

The two are deliberately separate: one is YouTube's side, the other is ours,
and only one of them is worth retrying.

### Related actors

`free-youtube-transcript` if you want the raw transcript and no summary,
`youtube-scraper` for search results, and `youtube-comments` for what people
said underneath.

# Actor input Schema

## `videoUrls` (type: `array`):

One per line. A full link, a youtu.be link, a Shorts link or a bare 11-character video id all work.

## `summaryStyle` (type: `string`):

Brief is a short paragraph. Detailed is four paragraphs. Bullets is six to ten complete sentences. Chapters breaks the video into its natural sections.

## `outputLanguage` (type: `string`):

Write the summary in this language regardless of what the video is in. Leave empty to follow the transcript.

## `preferred_languages` (type: `array`):

Caption languages to prefer, best first. YouTube often has several.

## `prefer_manual` (type: `boolean`):

Use human-written captions over auto-generated ones when both exist. Auto captions mishear names and numbers, which then end up in the summary.

## `includeTranscript` (type: `boolean`):

Add the raw transcript to each row. Off by default: it is the bulk of the payload and the summary is the point.

## `model` (type: `string`):

Leave empty for the default. Only set this if you know the model name you want.

## `concurrency` (type: `integer`):

How many transcripts to fetch at once.

## Actor input object example

```json
{
  "videoUrls": [
    "https://youtu.be/dQw4w9WgXcQ"
  ],
  "summaryStyle": "brief",
  "outputLanguage": "Dutch",
  "preferred_languages": [
    "nl",
    "en"
  ],
  "prefer_manual": true,
  "includeTranscript": false,
  "model": "",
  "concurrency": 3
}
```

# Actor output Schema

## `summaries` (type: `string`):

One row per video.

## `summary` (type: `string`):

Videos summarised, how many had no captions, and how many carried timestamps.

## `errors` (type: `string`):

Videos that could not be summarised.

# 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 = {
    "videoUrls": [
        "https://www.youtube.com/watch?v=aircAruvnKk"
    ],
    "preferred_languages": [
        "en"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/youtube-summarizer").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 = {
    "videoUrls": ["https://www.youtube.com/watch?v=aircAruvnKk"],
    "preferred_languages": ["en"],
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/youtube-summarizer").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 '{
  "videoUrls": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "preferred_languages": [
    "en"
  ]
}' |
apify call s-r/youtube-summarizer --silent --output-dataset

```

## MCP server setup

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

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/tLiey0s6ZLeK4gxZd/builds/FE52iv0R4ojkVh695/openapi.json
