# YouTube Video Details API — Views, Likes, Tags & Captions (`highbrow_fame/youtube-video-details-api`) Actor

Title, channel, views, likes, duration, publish date, description, tags, category, chapters, caption languages and thumbnails for any YouTube video link or id. No API key. Unofficial YouTube API.

- **URL**: https://apify.com/highbrow_fame/youtube-video-details-api.md
- **Developed by:** [yestrue](https://apify.com/highbrow_fame) (community)
- **Categories:** Social media, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 videos

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 Details API — Views, Likes, Tags & Captions

Everything the public watch page knows about a YouTube video as one clean JSON record: title, channel (id, name, handle, subscribers), exact view count, likes, comment count, duration, publish and upload dates, full description, keyword tags, category, chapters, the list of caption languages, thumbnails, hashtags, family-safe and unlisted flags and the number of countries the video is available in. Give it watch links, youtu.be short links, Shorts, embed or live links, or bare video ids. No API key, no quota, no cookies, no downloads — built on YouTube's public watch pages and its public oEmbed endpoint.

**Try it in 1 minute:**

1. Press **Start** — the prefilled input reads two videos: "Never Gonna Give You Up" (a watch link) and "Me at the zoo" (a youtu.be link).
2. Seconds later the **Output** tab shows both records with views, likes, comments, duration, dates, tags, chapters, caption languages and thumbnails.
3. Download JSON, CSV or Excel, or paste your own list — hundreds of links, one per line.

Price: **$4.00 per 1,000 videos** (one video = one record). Videos that do not exist, age-restricted or private videos, invalid inputs and reduced records (title, channel and thumbnail only) are free.

**Use it to:**

- Track views, likes and comments of your own or competitors' videos on a schedule and chart their growth.
- Enrich a list of video links from a spreadsheet, CRM or content calendar with title, channel, duration, category and tags.
- Audit which videos have captions (and in which languages) before ordering transcripts or translations.
- Pull chapters and descriptions to build show notes, timestamps or an index of a channel's catalogue.
- Feed an AI agent or RAG pipeline with structured video metadata instead of scraping HTML yourself.

### How it works

1. **Inputs** are parsed and deduplicated: `watch?v=`, `youtu.be/`, `/shorts/`, `/embed/`, `/live/`, mobile and music hosts, links with `t=` or `list=` parameters, and bare 11-character ids. Anything else gets a free `INVALID_INPUT` record.
2. **The watch page** (`youtube.com/watch?v=<id>&hl=en&gl=US`, desktop browser headers, no cookies) is fetched through Apify's residential proxies — YouTube withholds the page data from datacenter IPs, so they are the normal route here, not a retry. The page's embedded `ytInitialPlayerResponse` gives the video details, microformat (dates, category, flags, countries) and the caption track list; `ytInitialData` gives likes, comment count, chapter markers, hashtags and the channel's subscriber count.
3. **Chapters** come from the page's chapter markers; when a page has none, from timestamp lines in the description (`0:00 Intro`, `1:52 - Bridge`), applying YouTube's own rule (first at 0:00, in order, at least three).
4. **When YouTube withholds the page data** — the "Sign in to confirm you're not a bot" check, a consent interstitial — the public oEmbed endpoint still gives title, channel and thumbnail: you get a reduced record with `status: "REDUCED"`, `source: "oembed"` and the reason in `warnings` — and it is free. No bot check is bypassed and no sign-in is used.
5. A video that does not exist is a free `NOT_FOUND`; an age-restricted or private video (sign-in required) is a free `FAILED`. Phone numbers and e-mail addresses are removed from descriptions. Caption tracks are listed, never downloaded.

### Input

| Field | What it does |
|---|---|
| `videoUrls` | Videos to read, one per line: watch link, youtu.be link, Shorts/embed/live link or 11-character id. |
| `includeDescription` | Add the full description (default on). |
| `includeChapters` | Add chapters `[{ title, startSeconds, startTime }]` (default on). |
| `includeCaptionsList` | Add the caption languages on offer (default on). |
| `includeTags` | Add the uploader's keyword tags (default on). |
| `language` | YouTube interface language for the page, `hl` code (default `en`). |
| `maxConcurrency` | Parallel page fetches (default 3). |
| `proxyConfiguration` | Residential proxies by default (the normal route for this Actor). |

### Output

One record per video:

| Field | What it is |
|---|---|
| `videoId`, `url`, `title` | Identity and canonical watch URL |
| `channel` | `{ id, name, url, handle, subscribers }` |
| `views`, `likes`, `commentCount` | Exact views; likes (exact when the page has it); comments as the rounded count YouTube shows, as integers — `null` when hidden or off |
| `durationSeconds`, `duration` | Length in seconds and as `M:SS` / `H:MM:SS` |
| `publishedAt`, `uploadDate` | ISO 8601 dates |
| `description`, `tags[]`, `category`, `hashtags[]` | What the video is about |
| `chapters[]` | `{ title, startSeconds, startTime }` from the page's markers or the description |
| `captionLanguages[]`, `hasCaptions` | `{ languageCode, name, isAutoGenerated }` per caption track on offer |
| `thumbnails[]`, `thumbnail` | All sizes `{ url, width, height }` and the largest URL |
| `isLive`, `isLiveContent`, `isFamilySafe`, `isUnlisted`, `availableCountriesCount` | Flags and reach |
| `source`, `warnings[]` | `watch` for a full record, `oembed` for a reduced one; what could not be read and why |
| `input`, `status`, `error`, `scrapedAt` | What you gave, `OK` / `NOT_FOUND` / `FAILED` / `INVALID_INPUT`, the reason, and when |

#### Example

```json
{
  "input": "https://youtu.be/dQw4w9WgXcQ",
  "videoId": "dQw4w9WgXcQ",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "channel": { "id": "UCuAXFkgsw1L7xaCfnd5JJOw", "name": "Rick Astley", "url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", "handle": "@RickAstleyYT", "subscribers": 4560000 },
  "views": 1703456789,
  "likes": 18012345,
  "commentCount": 2300000,
  "durationSeconds": 213,
  "duration": "3:33",
  "publishedAt": "2009-10-25T06:57:33.000Z",
  "uploadDate": "2009-10-25T06:57:33.000Z",
  "description": "The official video for “Never Gonna Give You Up” by Rick Astley, remastered in 4K.\n\nChapters:\n0:00 - Intro\n0:18 - Verse 1\n0:43 - Chorus\n1:52 - Bridge",
  "tags": ["rick astley", "Never Gonna Give You Up", "rickroll", "4K", "Pop"],
  "category": "Music",
  "chapters": [
    { "title": "Intro", "startSeconds": 0, "startTime": "0:00" },
    { "title": "Verse 1", "startSeconds": 18, "startTime": "0:18" },
    { "title": "Chorus", "startSeconds": 43, "startTime": "0:43" },
    { "title": "Bridge", "startSeconds": 112, "startTime": "1:52" }
  ],
  "captionLanguages": [
    { "languageCode": "en", "name": "English", "isAutoGenerated": false },
    { "languageCode": "en", "name": "English (auto-generated)", "isAutoGenerated": true },
    { "languageCode": "es", "name": "Spanish", "isAutoGenerated": false }
  ],
  "hasCaptions": true,
  "thumbnails": [
    { "url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg", "width": 336, "height": 188 },
    { "url": "https://i.ytimg.com/vi_webp/dQw4w9WgXcQ/maxresdefault.webp", "width": 1920, "height": 1080 }
  ],
  "thumbnail": "https://i.ytimg.com/vi_webp/dQw4w9WgXcQ/maxresdefault.webp",
  "isLive": false,
  "isLiveContent": false,
  "isFamilySafe": true,
  "isUnlisted": false,
  "hashtags": ["#RickAstley", "#NeverGonnaGiveYouUp", "#4K"],
  "availableCountriesCount": 26,
  "source": "watch",
  "warnings": [],
  "status": "OK",
  "error": null,
  "scrapedAt": "2026-10-19T12:00:00.000Z"
}
```

### FAQ

**Is this an official API?** No, it's an unofficial API built on public pages — YouTube's watch pages and its public oEmbed endpoint, which need no key and no sign-in. The data is what the watch page itself shows; this Actor only shapes it into stable JSON records. YouTube's official Data API needs a key and has a daily quota; this one does not.

**Why is a record `source: "oembed"` with warnings?** YouTube sometimes serves a "Sign in to confirm you're not a bot" check or a cookie-consent page instead of the watch page. Those are not bypassed. The public oEmbed endpoint still answers with title, channel and thumbnail, so you get a free `REDUCED` record and the reason in `warnings`; the other fields are null. In our tests roughly one video in four was served that check even through residential proxies; run those videos again later.

**Why is a video FAILED or NOT_FOUND?** `NOT_FOUND`: the id does not exist or the video was removed. `FAILED` with "sign-in required": the video is age-restricted or private — reading it needs a signed-in account, which this Actor never uses. Both are free.

**Are likes and comment counts exact?** Views are exact. Likes are exact when the page carries the full number (it usually does), otherwise parsed from the rounded button text ("1.2M" → 1200000). The comment count is the rounded number YouTube shows ("2.3M" → 2300000). Hidden likes and disabled comments come back as `null`.

**Can I get transcripts?** No. This Actor lists the caption languages on offer (manual and auto-generated) so you know what exists, but never downloads caption tracks or transcripts.

**Like it?** A short review on the Store page helps other people find this Actor. Something missing or broken? Tell us on the Issues tab — we read every one.

### Related Actors

- [YouTube Transcript API](https://apify.com/highbrow_fame/youtube-transcript-fast) — captions, SRT and VTT of any video
- [Google Trends API](https://apify.com/highbrow_fame/google-trends-reliable) — interest over time and by region
- [Web Fetch API](https://apify.com/highbrow_fame/web-fetch-api) — any URL as HTML, text, Markdown or JSON
- [Article Extractor API](https://apify.com/highbrow_fame/article-extractor-api) — title, author, date and full text of any article
- [RSS & Atom Feed Reader](https://apify.com/highbrow_fame/rss-feed-reader) — any feed or website as one clean list

# Actor input Schema

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

YouTube videos, one per line: a watch link (with or without t= or list= parameters), youtu.be/<id>, /shorts/<id>, /embed/<id>, /live/<id>, or a bare 11-character video id. Duplicates are looked up once.

## `includeDescription` (type: `boolean`):

Add the full description to each record. Phone numbers and e-mail addresses in it are removed.

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

Add the chapters as \[{ title, startSeconds, startTime }] — from the page's chapter markers, or from timestamp lines in the description when the page has no markers.

## `includeCaptionsList` (type: `boolean`):

List the caption tracks the video offers as \[{ languageCode, name, isAutoGenerated }]. The list only — no transcripts are downloaded.

## `includeTags` (type: `boolean`):

Add the video's keyword tags (the ones the uploader set; not shown on the page).

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

YouTube interface language (hl) for the page, e.g. en, de, pt-BR. It changes the category name and the texts the counts are read from; en is the safest.

## `maxConcurrency` (type: `integer`):

How many watch pages are fetched at once. YouTube answers HTTP 429 to bursts from one IP; 3 is safe, and a 429 is waited out and retried.

## `proxyConfiguration` (type: `object`):

YouTube withholds video data from datacenter IPs, so every request goes through Apify residential proxies by default.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://youtu.be/jNQXAC9IVRw"
  ],
  "includeDescription": true,
  "includeChapters": true,
  "includeCaptionsList": true,
  "includeTags": true,
  "language": "en",
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Every result as a JSON record, with a status for each input.

## `resultsCsv` (type: `string`):

The same records as CSV, for a spreadsheet.

# 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=dQw4w9WgXcQ",
        "https://youtu.be/jNQXAC9IVRw"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("highbrow_fame/youtube-video-details-api").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=dQw4w9WgXcQ",
        "https://youtu.be/jNQXAC9IVRw",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("highbrow_fame/youtube-video-details-api").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=dQw4w9WgXcQ",
    "https://youtu.be/jNQXAC9IVRw"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call highbrow_fame/youtube-video-details-api --silent --output-dataset

```

## MCP server setup

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

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/PRimPFbxrqTnOiZBe/builds/jBJqrNhFSwBSiewBU/openapi.json
