# Video details

> A video's or Short's title, description, exact views and likes, publish date, length, tags, chapters and channel.

- **Request:** `GET https://api.lurkapi.com/v1/youtube/video`
- **Auth:** `x-api-key` header ([get a free key](https://lurkapi.com/login?next=/dashboard))
- **Cost:** 1 credit per call. Validation errors, `401`/`402`/`429` rejections and `5xx` failures are free; `not_found` is charged ([how charging works](https://lurkapi.com/docs.md#credits)).
- **MCP tool:** `youtube_video` on `https://api.lurkapi.com/mcp`
- **Freshness:** responses are cached for up to 1 hour
- **Try it live:** https://lurkapi.com/docs/youtube/video#try (no signup)
- **Platform:** [YouTube](https://lurkapi.com/docs/youtube.md) (youtube.com)
- **Web page:** https://lurkapi.com/docs/youtube/video

## When to use this

Use it to track how a video performs or to pull its metadata: exact view and like counts, the full description and its links, tags, category, chapters, the "Most replayed" graph and the videos YouTube recommends next. Works for Shorts too (`type: "short"`).

The comment count is rounded the way YouTube shows it; video comments returns the exact total. For what's said in the video, use video transcript.

Once in a while YouTube's player refuses us: then `type`, `durationMs`, `durationFormatted`, `keywords`, `genre`, `publishDate`, `uploadDate`, `isFamilySafe` and `isUnlisted` are null and everything else is still filled in.

Private, removed and unknown videos return 404 `not_found`.

## Parameters

All parameters go in the query string.

| Name | Type | Required | Default | Allowed values | Description | Example |
| --- | --- | --- | --- | --- | --- | --- |
| `url` | string | yes |  |  | The video's URL (watch, youtu.be, /shorts/, /live/ or /embed/ links all work) or its 11-character id, e.g. `https://www.youtube.com/watch?v=dQw4w9WgXcQ`. | `https://www.youtube.com/watch?v=dQw4w9WgXcQ` |

## Example request

Replace `YOUR_API_KEY` with your key, or set `LURKAPI_KEY` for the code. [Get a free key](https://lurkapi.com/login?next=/dashboard).

curl:

```bash
curl "https://api.lurkapi.com/v1/youtube/video?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ" \
  -H "x-api-key: YOUR_API_KEY"
```

JavaScript:

```js
const params = new URLSearchParams({
  url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
});
const res = await fetch(`https://api.lurkapi.com/v1/youtube/video?${params}`, {
  headers: { "x-api-key": process.env.LURKAPI_KEY },
});
const data = await res.json();
if (!data.success) throw new Error(`${data.code}: ${data.error}`);
console.log(data.descriptionLinks);
```

Python:

```python
import os
import requests

res = requests.get(
    "https://api.lurkapi.com/v1/youtube/video",
    params={
        "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    },
    headers={"x-api-key": os.environ["LURKAPI_KEY"]},
    timeout=60,
)
data = res.json()
if not data["success"]:
    raise RuntimeError(f"{data['code']}: {data['error']}")
print(data["descriptionLinks"])
```

## Example response

A real response from this endpoint, captured from the live API and trimmed to a couple of items. Strings over 96 characters (mostly signed media URLs) are cut short and end in `…`.

200 OK (application/json):

```json
{
  "success": true,
  "credits_remaining": 999986,
  "credits_charged": 1,
  "id": "dQw4w9WgXcQ",
  "type": "video",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "description": "The official video for “Never Gonna Give You Up” by Rick Astley. \n\nNever…",
  "descriptionLinks": [
    {
      "text": "https://linktr.ee/rickastleynever",
      "url": "https://linktr.ee/rickastleynever"
    },
    {
      "text": "https://RickAstley.lnk.to/YTSubID",
      "url": "https://RickAstley.lnk.to/YTSubID"
    },
    {
      "text": "https://RickAstley.lnk.to/FBFollowID",
      "url": "https://RickAstley.lnk.to/FBFollowID"
    },
    {
      "text": "https://RickAstley.lnk.to/TwitterID",
      "url": "https://RickAstley.lnk.to/TwitterID"
    },
    {
      "text": "https://RickAstley.lnk.to/InstagramID",
      "url": "https://RickAstley.lnk.to/InstagramID"
    },
    {
      "text": "https://RickAstley.lnk.to/storeID",
      "url": "https://RickAstley.lnk.to/storeID"
    },
    {
      "text": "https://RickAstley.lnk.to/TikTokID",
      "url": "https://RickAstley.lnk.to/TikTokID"
    },
    {
      "text": "https://RickAstley.lnk.to/SpotifyID",
      "url": "https://RickAstley.lnk.to/SpotifyID"
    },
    {
      "text": "https://RickAstley.lnk.to/AppleMusicID",
      "url": "https://RickAstley.lnk.to/AppleMusicID"
    },
    {
      "text": "https://RickAstley.lnk.to/AmazonMusicID",
      "url": "https://RickAstley.lnk.to/AmazonMusicID"
    },
    {
      "text": "https://RickAstley.lnk.to/DeezerID",
      "url": "https://RickAstley.lnk.to/DeezerID"
    }
  ],
  "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
  "viewCountText": "1,821,634,661 views",
  "viewCountInt": 1821634661,
  "likeCountText": "19M",
  "likeCountInt": 19439173,
  "commentCountText": "2.4M",
  "commentCountInt": 2400000,
  "publishDate": "2009-10-24T23:57:33-07:00",
  "uploadDate": "2009-10-24T23:57:33-07:00",
  "publishDateText": "Oct 24, 2009",
  "channel": {
    "id": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "url": "https://www.youtube.com/@RickAstleyYT",
    "handle": "RickAstleyYT",
    "title": "Rick Astley",
    "subscriberCountText": "4.55M subscribers",
    "subscriberCount": 4550000,
    "isVerified": true,
    "avatar": "https://yt3.ggpht.com/_ShEGOdg-t5YGJse14Ooq6FYBZqX_QSlhaTNjG06miYusm5lWm…"
  },
  "chapters": [],
  "keywords": [
    "rick astley",
    "Never Gonna Give You Up",
    "nggyu",
    "never gonna give you up lyrics",
    "rick rolled",
    "Rick Roll",
    "rick astley official",
    "rickrolled",
    "Fortnite song",
    "Fortnite event",
    "Fortnite dance",
    "fortnite never gonna give you up",
    "rick roll",
    "rickrolling",
    "rick rolling",
    "never gonna give you up",
    "80s music",
    "rick astley new",
    "animated video",
    "rickroll",
    "meme songs",
    "never gonna give u up lyrics",
    "Rick Astley 2022",
    "never gonna let you down",
    "animated",
    "rick rolls 2022",
    "never gonna give you up karaoke"
  ],
  "genre": "Music",
  "durationMs": 213000,
  "durationFormatted": "00:03:33",
  "isFamilySafe": true,
  "isUnlisted": false,
  "most_replayed": {
    "markers": [
      {
        "startMillis": 0,
        "durationMillis": 2140,
        "intensityScoreNormalized": 1
      },
      {
        "startMillis": 2140,
        "durationMillis": 2140,
        "intensityScoreNormalized": 0.4217676376522385
      }
    ],
    "ranges": [
      {
        "visibleTimeRangeStartMillis": 0,
        "visibleTimeRangeEndMillis": 6420,
        "decorationTimeMillis": 2140,
        "label": "Most replayed"
      }
    ]
  },
  "watchNextVideos": [
    {
      "id": "NWItxGY5NNk",
      "title": "80'S MUSIC ON THE ROAD | 2 Hours of Classic '80s Hits",
      "thumbnail": "https://i.ytimg.com/vi/NWItxGY5NNk/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFX…",
      "channel": {
        "id": "UCkUSPjRL8md2hlE8bNXAT-A",
        "url": "https://www.youtube.com/@everysongisascar",
        "handle": "everysongisascar",
        "title": "every song is a scar"
      },
      "publishedTimeText": "3 months ago",
      "viewCountText": "3.9M",
      "viewCountInt": 3900000,
      "lengthText": "2:16:49",
      "lengthInSeconds": 8209,
      "videoUrl": "https://www.youtube.com/watch?v=NWItxGY5NNk"
    },
    {
      "id": "yPYZpwSpKmA",
      "title": "Rick Astley - Together Forever (Official Video) [4K Remaster]",
      "thumbnail": "https://i.ytimg.com/vi/yPYZpwSpKmA/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFX…",
      "channel": {
        "id": "UCuAXFkgsw1L7xaCfnd5JJOw",
        "url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
        "handle": null,
        "title": "Rick Astley"
      },
      "publishedTimeText": "16 years ago",
      "viewCountText": "206M",
      "viewCountInt": 206000000,
      "lengthText": "3:24",
      "lengthInSeconds": 204,
      "videoUrl": "https://www.youtube.com/watch?v=yPYZpwSpKmA"
    }
  ]
}
```

## Response fields

Every field of a successful response. `[]` marks a list: `a[].b` is the `b` of each item in `a`. **nullable** fields can be `null`; **optional** fields can be missing.

| Field | Type | Description |
| --- | --- | --- |
| `success` | `true` | Always true here; errors have `success: false`. |
| `credits_remaining` | `number` | Your balance after this call. On anonymous playground calls: free tries left today. |
| `credits_charged` | `number` | Credits this call cost; 0 on free endpoints. On anonymous playground calls: tries used (1). |
| `id` | `string` | Video id, e.g. `dQw4w9WgXcQ`. |
| `type` | `string`, nullable | `short` for YouTube Shorts, else `video`. null in the rare case the player details were unavailable (see `durationMs`). |
| `url` | `string` | Canonical link: /shorts/<id> for Shorts, /watch?v=<id> otherwise. |
| `title` | `string` | Video title. |
| `description` | `string` | Full description, plain text. |
| `descriptionLinks` | `object[]` | Outbound links in the description, in order. |
| `descriptionLinks[].text` | `string` | The link as it appears in the description. |
| `descriptionLinks[].url` | `string` | Where it goes (YouTube's redirect wrapper removed). |
| `thumbnail` | `string` | Largest thumbnail URL. |
| `viewCountText` | `string`, nullable | Views as YouTube shows them, e.g. "1,821,613,271 views". |
| `viewCountInt` | `number`, nullable | Exact view count. |
| `likeCountText` | `string`, nullable | Likes as YouTube shows them, e.g. "19M"; null when the creator hides likes. |
| `likeCountInt` | `number`, nullable | Exact like count. null when the creator hides likes. |
| `commentCountText` | `string`, nullable | Comments as YouTube shows them, e.g. "2.4M"; null when comments are off. |
| `commentCountInt` | `number`, nullable | Comment count from that text, so rounded above 1,000 (2.4M → 2400000). The comments endpoint returns the exact total. |
| `publishDate` | `string`, nullable | Published at, ISO 8601 with YouTube's offset, e.g. `2009-10-24T23:57:33-07:00`. null if unavailable. |
| `uploadDate` | `string`, nullable | Uploaded at, ISO 8601 (differs from publishDate for scheduled videos and premieres). null if unavailable. |
| `publishDateText` | `string`, nullable | The date line under the video, e.g. "Oct 24, 2009" or "Premiered 3 hours ago". |
| `channel` | `object` | The channel that posted it. |
| `channel.id` | `string`, nullable | Channel id, `UC…`. |
| `channel.url` | `string`, nullable | Channel page, e.g. `https://www.youtube.com/@RickAstleyYT`. |
| `channel.handle` | `string`, nullable | Handle without the @, e.g. `RickAstleyYT`; null if YouTube shows none. |
| `channel.title` | `string`, nullable | Channel name. |
| `channel.subscriberCountText` | `string`, nullable | Subscribers as YouTube shows them, e.g. "4.55M subscribers". |
| `channel.subscriberCount` | `number`, nullable | Subscribers as a number, from that rounded text (4.55M → 4550000). |
| `channel.isVerified` | `boolean` | Has a verified or official artist badge. |
| `channel.avatar` | `string`, nullable | Channel avatar URL. |
| `chapters` | `object[]` | Chapters from the description (or YouTube's automatic ones), in order. Empty if the video has none. |
| `chapters[].title` | `string` | Chapter title. |
| `chapters[].startMs` | `number` | Where the chapter starts, ms from the start of the video. |
| `chapters[].thumbnail` | `string`, nullable | Chapter thumbnail URL. |
| `keywords` | `string[]`, nullable | The creator's tags. null if unavailable. |
| `genre` | `string`, nullable | YouTube category, e.g. "Music" or "Education". null if unavailable. |
| `durationMs` | `number`, nullable | Length in ms. null if unavailable: this and the other fields marked "if unavailable" come from YouTube's player, which occasionally refuses us; the rest of the response is still complete. |
| `durationFormatted` | `string`, nullable | Length as `HH:MM:SS`, e.g. "00:03:33". null if unavailable. |
| `isFamilySafe` | `boolean`, nullable | YouTube considers it family safe. null if unavailable. |
| `isUnlisted` | `boolean`, nullable | Unlisted (only people with the link can find it). null if unavailable. |
| `most_replayed` | `object`, nullable | The "Most replayed" graph. null when YouTube doesn't show one (newer or less-watched videos). |
| `most_replayed.markers` | `object[]` | The replay graph over the timeline, usually 100 equal slices. |
| `most_replayed.markers[].startMillis` | `number` | Start of this slice of the video, ms. |
| `most_replayed.markers[].durationMillis` | `number` | Length of the slice, ms. |
| `most_replayed.markers[].intensityScoreNormalized` | `number` | How often this slice is replayed, 0–1 (1 = the most replayed slice). |
| `most_replayed.ranges` | `object[]` | Ranges YouTube highlights as most replayed. |
| `most_replayed.ranges[].visibleTimeRangeStartMillis` | `number` | Start of the highlighted range, ms. |
| `most_replayed.ranges[].visibleTimeRangeEndMillis` | `number` | End of the highlighted range, ms. |
| `most_replayed.ranges[].decorationTimeMillis` | `number` | The peak YouTube points at, ms. |
| `most_replayed.ranges[].label` | `string`, nullable | YouTube's label, e.g. "Most replayed". |
| `watchNextVideos` | `object[]` | The "Up next" videos YouTube recommends beside this one (videos only, no mixes or playlists). |
| `watchNextVideos[].id` | `string` | Video id. |
| `watchNextVideos[].title` | `string`, nullable | Video title. |
| `watchNextVideos[].thumbnail` | `string`, nullable | Thumbnail URL. |
| `watchNextVideos[].channel` | `object` | The channel that posted it. |
| `watchNextVideos[].channel.id` | `string`, nullable | Channel id, `UC…`. |
| `watchNextVideos[].channel.url` | `string`, nullable | Channel page, e.g. `https://www.youtube.com/@RickAstleyYT`. |
| `watchNextVideos[].channel.handle` | `string`, nullable | Handle without the @, e.g. `RickAstleyYT`; null if YouTube shows none. |
| `watchNextVideos[].channel.title` | `string`, nullable | Channel name. |
| `watchNextVideos[].publishedTimeText` | `string`, nullable | When it was posted, relative, e.g. "3 months ago". |
| `watchNextVideos[].viewCountText` | `string`, nullable | Views as YouTube shows them, e.g. "3.9M". |
| `watchNextVideos[].viewCountInt` | `number`, nullable | Views from that rounded text (3.9M → 3900000). |
| `watchNextVideos[].lengthText` | `string`, nullable | Length as shown on the thumbnail, e.g. "4:05". |
| `watchNextVideos[].lengthInSeconds` | `number`, nullable | Length in seconds. |
| `watchNextVideos[].videoUrl` | `string` | Link to the video. |

## Caching and freshness

Responses are cached for up to 1 hour, so a repeat call within that window can return the same data. It still costs 1 credit.

## Errors

Errors return `{ success: false, error, code, docs }` with the HTTP status below. Validation errors, `401`/`402`/`429` rejections and `5xx` failures are free; `not_found` is charged ([how charging works](https://lurkapi.com/docs.md#credits)). [All error codes](https://lurkapi.com/docs.md#errors).

| Status | Code | Meaning |
| --- | --- | --- |
| 401 | `missing_api_key` | No API key. Send it in the `x-api-key` header. |
| 401 | `invalid_api_key` | The key is unknown or was revoked. |
| 402 | `insufficient_credits` | Not enough credits for this call. Buy a pack or wait for tomorrow's top-up. |
| 404 | `not_found` | The endpoint, or the thing you asked for (ad, post, subreddit), doesn't exist. Charged when the platform was checked. |
| 405 | `method_not_allowed` | Endpoints take GET with query params. |
| 429 | `rate_limited` | Too many calls at once. Wait for the `retry-after` seconds, then retry. |
| 500 | `internal_error` | Something broke on our side. Retry; 5xx errors are free. |
| 502 | `upstream_error` | The platform didn't give a usable answer. Retry; 5xx errors are free. |
| 503 | `upstream_busy` | All our connections to the platform are busy. Retry in a few seconds; 5xx errors are free. |
| 504 | `upstream_timeout` | The platform took over 30 seconds to answer. Retry; timeouts are free. |

## Use it in Claude

Once LurkAPI is [connected to Claude](https://lurkapi.com/docs.md#claude), this endpoint is the `youtube_video` tool. Ask in plain English, for example:

Ask Claude:

```text
Use LurkAPI's youtube_video with url "https://www.youtube.com/watch?v=dQw4w9WgXcQ" and summarize what you find.
```

Claude calls `youtube_video` with arguments like these, and each call costs 1 credit:

Tool arguments:

```json
{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}
```

Tool results skip nulls and empty lists to save tokens.

---

Previous: [Post comments](https://lurkapi.com/docs/reddit/post-comments.md) · Next: [Video transcript](https://lurkapi.com/docs/youtube/transcript.md)
