{
  "openapi": "3.0.1",
  "info": {
    "title": "YouTube Transcript, Subtitles & Comments Scraper",
    "description": "YouTube transcript scraper & API: get subtitles & captions as plain text, SRT, VTT, timestamped JSON or LLM-ready chunks from videos, Shorts, channels, playlists and search. Any language or translated, plus chapters, metadata and comments. $2 per 1,000 transcripts; videos without captions are free.",
    "version": "1.0",
    "x-build-id": "eZwDecGKF80x4osZq"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/aaronoptimus~youtube-transcripts-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-aaronoptimus-youtube-transcripts-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/aaronoptimus~youtube-transcripts-scraper/runs": {
      "post": {
        "operationId": "runs-sync-aaronoptimus-youtube-transcripts-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/aaronoptimus~youtube-transcripts-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-aaronoptimus-youtube-transcripts-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "startUrls": {
            "title": "YouTube URLs or video IDs",
            "type": "array",
            "description": "Video URLs (watch, youtu.be, Shorts, live, embed), channel URLs (@handle, /channel/UC…, /c/…, /user/…), playlist URLs, search result URLs (youtube.com/results?search_query=…) or bare 11-character video IDs — one per line. Channels, playlists and searches are expanded to their videos for free. Free plan: 100 videos per run.",
            "items": {
              "type": "string"
            }
          },
          "searchQueries": {
            "title": "Search YouTube",
            "type": "array",
            "description": "Search terms, one per line, e.g. \"how to start a podcast\". Each search is expanded to its video results (see \"Max videos per search\"); the search itself is free, you pay per transcript delivered.",
            "items": {
              "type": "string"
            }
          },
          "maxVideosPerSearch": {
            "title": "Max videos per search",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "How many video results to take from each search term. YouTube serves about 20 results per page; the scraper pages through them until it has this many (or YouTube has no more).",
            "default": 20
          },
          "searchSort": {
            "title": "Search: sort by",
            "enum": [
              "relevance",
              "popularity"
            ],
            "type": "string",
            "description": "YouTube's own ordering: relevance, or popularity (most viewed first). YouTube no longer offers sorting by upload date; use \"Search: uploaded within\" or \"Published after\" to get recent videos.",
            "default": "relevance"
          },
          "searchUploadDate": {
            "title": "Search: uploaded within",
            "enum": [
              "any",
              "today",
              "week",
              "month",
              "year"
            ],
            "type": "string",
            "description": "YouTube's upload-date filter for searches.",
            "default": "any"
          },
          "searchSubtitlesOnly": {
            "title": "Search: only videos with subtitles/CC",
            "type": "boolean",
            "description": "Apply YouTube's \"Subtitles/CC\" search filter. YouTube applies it to uploaded subtitles, so videos that only have auto-generated captions may be left out.",
            "default": false
          },
          "maxVideosPerSource": {
            "title": "Max videos per channel/playlist",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "How many videos to take from each channel (newest first) or playlist. With \"Include Shorts\" / \"Include live streams\", this limit applies to each of a channel's Videos, Shorts and Live tabs. Listing is free; you pay per transcript delivered.",
            "default": 50
          },
          "includeTranscript": {
            "title": "Transcript",
            "type": "boolean",
            "description": "Get the transcript (subtitles / captions) as plain text, paragraphs, SRT, WebVTT and timed segments. Videos without captions are delivered with hasTranscript: false and are not charged.",
            "default": true
          },
          "languages": {
            "title": "Transcript languages (in order of preference)",
            "type": "array",
            "description": "Caption language codes to look for, in order, e.g. en, es, pt-BR. The first one the video has is used (uploaded captions before auto-generated ones). Leave empty for the video's original language. (The older single \"language\" field is still accepted.)",
            "items": {
              "type": "string"
            }
          },
          "whenLanguageMissing": {
            "title": "If none of these languages exists",
            "enum": [
              "original",
              "translate",
              "skip"
            ],
            "type": "string",
            "description": "What to do when a video has none of your languages: return the video's original captions (with a note), translate the original captions into your first language with YouTube's translation, or skip the transcript (delivered with reason \"language-unavailable\", not charged).",
            "default": "original"
          },
          "translateTo": {
            "title": "Always translate to",
            "type": "string",
            "description": "Optional. Language code to translate every transcript into with YouTube's own translation, e.g. en, es, fr. Leave empty for no translation."
          },
          "outputFormat": {
            "title": "Output format",
            "enum": [
              "items",
              "rows"
            ],
            "type": "string",
            "description": "Items: one rich JSON record per video with the transcript, chapters and comments (best for API, code and AI). Rows: one flat row per transcript segment (or chunk) and per comment with the same columns everywhere (best for CSV, Excel, Google Sheets).",
            "default": "items"
          },
          "chunkSeconds": {
            "title": "Chunk length (seconds)",
            "minimum": 0,
            "maximum": 3600,
            "type": "integer",
            "description": "For RAG / LLM pipelines: also split the transcript into chunks of up to this many seconds (transcript.chunks, each with start/end time, a link to that moment and its chapter). Chunks never cross a chapter. 0 = off. Can be combined with \"Chunk size (words)\".",
            "default": 0
          },
          "chunkWords": {
            "title": "Chunk size (words)",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Split the transcript into chunks of up to this many words (e.g. 300). 0 = off. When both chunk settings are set, a chunk ends at whichever limit comes first.",
            "default": 0
          },
          "leanOutput": {
            "title": "Lean items (no SRT, VTT, segments)",
            "type": "boolean",
            "description": "Items format only: leave out transcript.srt, transcript.vtt and transcript.segments so each record stays small. Plain text, paragraphs, chunks, chapters and metadata stay.",
            "default": false
          },
          "includeComments": {
            "title": "Comments",
            "type": "boolean",
            "description": "Also collect comments (author, text, likes, date, pinned / hearted / creator flags). Charged per comment delivered. Free plan: 50 per video.",
            "default": false
          },
          "maxCommentsPerVideo": {
            "title": "Max comments per video",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Upper limit of comments (replies included) per video. Free plan: capped at 50.",
            "default": 100
          },
          "commentSort": {
            "title": "Comment order",
            "enum": [
              "top",
              "newest"
            ],
            "type": "string",
            "description": "Top comments (YouTube's ranking) or newest first.",
            "default": "top"
          },
          "includeReplies": {
            "title": "Include replies",
            "type": "boolean",
            "description": "Also collect replies to comments. Replies count toward \"Max comments per video\" and are charged like comments.",
            "default": false
          },
          "publishedAfter": {
            "title": "Published after",
            "type": "string",
            "description": "Only videos from channels, playlists and searches published after this date or within this age: a date like 2026-09-01, or an age like \"7 days\", \"24 hours\", \"2 weeks\". Videos you paste directly are always processed. Older videos are left out and not charged."
          },
          "includeShorts": {
            "title": "Include Shorts",
            "type": "boolean",
            "description": "Channels: also take videos from the Shorts tab. Searches: include Shorts in the results. Off: channels use the Videos tab and searches ask YouTube for regular videos only.",
            "default": false
          },
          "includeLiveStreams": {
            "title": "Include live streams (channels)",
            "type": "boolean",
            "description": "Channels: also take finished live streams from the Live tab. Streams that are live right now or scheduled have no transcript yet and are always left out. Searches include finished streams anyway.",
            "default": false
          },
          "skipAlreadyScraped": {
            "title": "Skip videos already scraped in earlier runs",
            "type": "boolean",
            "description": "Remember the IDs of videos whose transcript was delivered (in a named key-value store in your Apify account) and skip them in later runs, so scheduled runs only pay for new uploads. Videos without a transcript yet are tried again next time.",
            "default": false
          },
          "skipAlreadyScrapedStore": {
            "title": "Already-scraped list name",
            "type": "string",
            "description": "Name of the key-value store that keeps the already-scraped video IDs. Use a different name per schedule to keep separate lists; delete the store to start over. Letters, digits and hyphens.",
            "default": "youtube-transcripts-seen"
          },
          "proxyConfiguration": {
            "title": "Proxy",
            "type": "object",
            "description": "YouTube blocks repeated anonymous requests from one IP. Apify Proxy is recommended; sessions and IPs rotate automatically.",
            "default": {
              "useApifyProxy": true
            }
          },
          "useResidentialFallback": {
            "title": "Fall back to residential proxy when blocked",
            "type": "boolean",
            "description": "If YouTube keeps blocking the default proxy, switch to Apify residential proxy automatically. No extra cost to you.",
            "default": true
          },
          "maxConcurrency": {
            "title": "Parallel sessions",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "How many videos to process at the same time, each with its own session (an IP that YouTube accepts is shared by at most two). Higher is faster for big lists.",
            "default": 4
          },
          "maxRetries": {
            "title": "Max retries per request",
            "minimum": 0,
            "maximum": 15,
            "type": "integer",
            "description": "How many times to retry with a fresh session and IP when YouTube blocks or throttles a request.",
            "default": 8
          },
          "maxSecondsPerVideo": {
            "title": "Time limit per video (seconds)",
            "minimum": 20,
            "maximum": 900,
            "type": "integer",
            "description": "Stop retrying a video after this long so one stubborn video can't stall the run. The video is reported as failed and not charged.",
            "default": 90
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}