Reach for this when structured YouTube data is the goal: video metadata, transcripts for analysis, channel upload history, search results or playlist contents, with no Google Cloud project and no quota units. Triggers on YouTube links, creator names and topic research even when unstated. Skip it for uploads and text-only research.
Installs into .claude/skills of the current project.
Are you the author of Youtube Data?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/artemchuikin-youtube-data-youtube-skills)
---
name: youtube-data
description: "Reach for this when structured YouTube data is the goal: video metadata, transcripts for analysis, channel upload history, search results or playlist contents, with no Google Cloud project and no quota units. Triggers on YouTube links, creator names and topic research even when unstated. Skip it for uploads and text-only research."
version: "1.0.0"
user-invocable: true
compatibility: Requires internet access to reach api.transcriptout.com. No additional runtimes or dependencies needed.
required_environment_variables:
- name: TRANSCRIPTOUT_API_KEY
prompt: Your TranscriptOut API key (starts with sk_)
help: Free account at https://transcriptout.com (100 credits on signup, no card). Create the key in the dashboard.
required_for: all API requests
metadata: {"openclaw":{"emoji":"📊","requires":{"env":["TRANSCRIPTOUT_API_KEY"]},"primaryEnv":"TRANSCRIPTOUT_API_KEY","homepage":"https://transcriptout.com"},"hermes":{"tags":["youtube","data","metadata","api","channels","playlists"],"category":"media"}}
---
# YouTube Data
YouTube data access via [TranscriptOut.com](https://transcriptout.com): a lightweight alternative to Google's YouTube Data API.
## Setup
If `$TRANSCRIPTOUT_API_KEY` is not set, read [references/auth-setup.md](references/auth-setup.md) and follow the instructions there to get and store the key.
## Required Header
Every request needs one header:
- **Authorization:** `Bearer $TRANSCRIPTOUT_API_KEY`
Every response is one JSON envelope. Success: `{"ok": true, "request_id": "...", "data": {...}}`. Error: `{"ok": false, "code": "...", "detail": "...", "request_id": "..."}`. Branch on the machine-readable `code`, not on the human text. The remaining credit balance rides in the `X-Credits-Remaining` response header.
## API Reference
Base URL: `https://api.transcriptout.com/v1`. Full reference with the latest parameters and schemas: [transcriptout.com/docs](https://transcriptout.com/docs).
## GET /v1/video · 1 credit
Metadata for one video (title, channel, duration, views, thumbnails) plus the list of available transcript languages, WITHOUT downloading the subtitles.
```http
GET https://api.transcriptout.com/v1/video?id=VIDEO_URL_OR_ID
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
```
**Credit hygiene:** if the transcript is wanted anyway, call `/v1/transcript` with `video_metadata=true` instead. One call and one credit against two.
## Transcript data · 1 credit
Fetch the transcript of any YouTube video.
```http
GET https://api.transcriptout.com/v1/transcript?video=VIDEO_URL_OR_ID&format=text
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
```
Accepts full URLs (`youtube.com/watch?v=ID`), short URLs (`youtu.be/ID`), shorts (`youtube.com/shorts/ID`), or bare video IDs.
**Default for agents:** use `format=text` unless you need timestamps. Plain text is the cheapest form to reason over. Use `format=json` to cite or seek to exact moments. Add `video_metadata=true` when the title/channel is also wanted: same call, same 1 credit.
| Param | Required | Default | Values |
| ---------------- | -------- | ------- | ------ |
| `video` | yes | - | YouTube URL (full/short/shorts) or 11-char video ID |
| `lang` | no | `en` | language code of the track (`en`, `de`, ...) |
| `format` | no | `json` | `json`, `text`, `srt`, `vtt`, `srv3` |
| `kind` | no | manual if present | `manual`, `auto` |
| `segment` | no | auto tracks: 180 (80 for `srt`/`vtt`). Manual tracks keep the author's lines | 20-5000, max characters per segment |
| `video_metadata` | no | `false` | `true` adds `data.metadata` (title, channel, duration, views) for the same 1 credit |
| `download` | no | `false` | `true` returns the raw file instead of the JSON envelope (`text`/`srt`/`vtt`/`srv3` only) |
`segment` controls the size of the pieces: 500-1500 characters makes chunks with enough context for embeddings and retrieval. Left out, an auto-generated track is cut into ~180-character segments and a manual track is returned exactly as its author broke it.
**Response** for `format=json`. With `format=text`/`srt`/`vtt`/`srv3` the `transcript` field is one string in that format:
```json
{
"ok": true,
"request_id": "req_...",
"data": {
"video_id": "dQw4w9WgXcQ",
"language": "en",
"kind": "manual",
"transcript": [
{ "text": "Never gonna give you up", "start": 18.0, "duration": 4.12 },
{ "text": "Never gonna let you down", "start": 22.12, "duration": 3.85 }
],
"available_langs": [
{ "code": "en", "kind": "manual", "name": "English" },
{ "code": "en", "kind": "auto", "name": "English (auto-generated)" }
]
}
}
```
## GET /v1/search · 1 credit/page
Search YouTube for videos or channels.
```http
# Videos
GET https://api.transcriptout.com/v1/search?q=QUERY&type=video&limit=20
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
# Channels
GET https://api.transcriptout.com/v1/search?q=QUERY&type=channel&limit=10
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
# Next page
GET https://api.transcriptout.com/v1/search?next_page_token=TOKEN
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
```
| Param | Required | Default | Validation |
| ----------------- | -------- | ------- | ---------- |
| `q` | yes* | - | the query (*or pass `next_page_token`) |
| `type` | no | `video` | `video`, `channel` |
| `limit` | no | `20` | 1-50 |
| `next_page_token` | no | - | token from a previous page |
The response carries `next_page_token` and `has_more`. Video entries have `video_id`, `title`, `channel`, `duration` (`"M:SS"`), `view_count`, `published`, `url`, `thumbnails`.
## GET /v1/channel/videos · 1 credit/page
Every video from a channel's Videos tab, newest first.
```http
# First page (100 videos)
GET https://api.transcriptout.com/v1/channel/videos?name=@3blue1brown
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
# Next pages
GET https://api.transcriptout.com/v1/channel/videos?next_page_token=TOKEN
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
# IDs only, 500 per page (feed these into the bulk job)
GET https://api.transcriptout.com/v1/channel/videos?name=@3blue1brown&ids_only=true
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
```
Provide `name` on the first call and only `next_page_token` afterwards. `limit` goes up to 100, or up to 500 with `ids_only=true` (the response is then `video_ids[]` instead of full video objects). The response carries `next_page_token` and `has_more`.
## GET /v1/playlist/videos · 1 credit/page
Every video of a playlist, in playlist order.
```http
# First page (100 videos)
GET https://api.transcriptout.com/v1/playlist/videos?id=PL_ID_OR_URL
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
# Next pages
GET https://api.transcriptout.com/v1/playlist/videos?next_page_token=TOKEN
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
# IDs only, 500 per page (feed these into the bulk job)
GET https://api.transcriptout.com/v1/playlist/videos?id=PL_ID_OR_URL&ids_only=true
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
```
`id` accepts a `PL...` playlist ID or any URL with `list=`. `limit` goes up to 100, or up to 500 with `ids_only=true`. The response carries `playlist`, `title`, `count`, `videos[]` (or `video_ids[]`), `next_page_token` and `has_more`.
## Credit Costs
| Endpoint | Cost |
| -------- | ---- |
| transcript | 1 |
| video (metadata) | 1 |
| search | 1/page |
| channel/latest | 1 |
| channel/videos | 1/page |
| channel/search | 1/page |
| playlist/videos | 1/page |
| playlist/search | 1 |
| transcripts (bulk job) | 1 per video |
| job status / results / cancel | **free** |
Credits are refunded automatically when a call fails before reaching YouTube (validation, rate limit, service capacity). A definitive "this video has no captions" (404) is an answer and is billed like one.
## Errors
| Code | Meaning | Action |
| ---- | ------- | ------ |
| 400/422 | Bad parameter | Fix the request. Credit refunded automatically |
| 401 | Bad or missing API key | Check the key. It must start with `sk_` |
| 402 | Out of credits | [transcriptout.com/billing](https://transcriptout.com/billing) |
| 404 | No captions on that language/track, or bad ID | Definitive answer, do not retry. Try another `lang` or `kind=auto`. Billed |
| 410 | Video removed | Do not retry |
| 451 | Age-restricted or members-only | Do not retry |
| 429 | Rate limit (200 req/min per key) | Wait, respect `Retry-After`. Refunded |
| 502 | Failed on YouTube's side | One retry is reasonable. Billed |
| 503 | Service at capacity | Retry after `Retry-After`. Refunded |
Every error body carries a machine-readable `code` and a `request_id`. Include the `request_id` when contacting support.
## Copy-paste examples
Every request in this file as a ready-to-run one-liner: [references/curl-examples.md](references/curl-examples.md)