{
  "openapi": "3.0.1",
  "info": {
    "title": "YouTube Metadata Scraper By Duration, Date & Video Type",
    "description": "YouTube Metadata Scraper extracts detailed metadata from YouTube videos, including titles, descriptions, tags, thumbnails, durations, upload dates, and engagement stats. Ideal for SEO research, content analysis, trend tracking, and automating structured YouTube data collection",
    "version": "0.1",
    "x-build-id": "jonxnGeKTrwlPYz4y"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/simpleapi~youtube-metadata-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-simpleapi-youtube-metadata-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/simpleapi~youtube-metadata-scraper/runs": {
      "post": {
        "operationId": "runs-sync-simpleapi-youtube-metadata-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/simpleapi~youtube-metadata-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-simpleapi-youtube-metadata-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": {
          "keywords": {
            "title": "🎯 Search phrases",
            "type": "array",
            "description": "One phrase per line. Each phrase is run through YouTube search with your filter token attached. Example: `drone footage` + duration `Over 20 minutes` + feature `4K`.",
            "items": {
              "type": "string"
            }
          },
          "max_results_per_keyword": {
            "title": "📦 Videos to keep per phrase",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "How many filtered videos to enrich per phrase. Deep paging goes through YouTube's own continuation endpoint; a filtered phrase realistically yields 130–480 results before YouTube runs out of pages, so anything higher simply stops early. Default 20.",
            "default": 20
          },
          "urls": {
            "title": "🔗 Specific videos (skips the search)",
            "type": "array",
            "description": "Optional. Watch links, `youtu.be` links, `/shorts/`, `/live/`, `/embed/` links or bare 11-character video IDs. Videos listed here bypass every search filter and are always scraped.",
            "items": {
              "type": "string"
            }
          },
          "videoDuration": {
            "title": "⏱️ Video length band",
            "enum": [
              "any",
              "under_3",
              "under_4",
              "3_20",
              "4_20",
              "over_20"
            ],
            "type": "string",
            "description": "YouTube's live filter bar only offers Under 3 / 3–20 / Over 20; those three were exact (0 out-of-band results in 84 deep-paged rows). The two legacy 4-minute bands still work on the wire but are approximate at the boundary — a live run returned one 239-second video inside the 4-to-20 band — and YouTube lights no chip for them, so they never appear in the `appliedFilters` column. Use the exact second-level window below when the boundary matters.",
            "default": "any"
          },
          "uploadDate": {
            "title": "🗓️ Upload-date bucket",
            "enum": [
              "any",
              "hour",
              "today",
              "week",
              "month",
              "year"
            ],
            "type": "string",
            "description": "Coarse recency bucket. If you also set an exact date range below, the exact range wins and this bucket is ignored by YouTube's ranker. `Last hour` is enforced (measured: 15/18 results minutes old vs 8/20 hours old with no filter) but lights no chip.",
            "default": "any"
          },
          "resultType": {
            "title": "📺 Result type",
            "enum": [
              "video",
              "shorts",
              "movie"
            ],
            "type": "string",
            "description": "Only these three types return actual videos. Channels and playlists are deliberately not offered: those filters return channel and playlist cards, so a run would finish with zero video rows. Shorts results arrive in two different card layouts depending on the phrase — both are parsed.",
            "default": "video"
          },
          "videoFeatures": {
            "title": "🏷️ Required features",
            "type": "array",
            "description": "Pick any combination — YouTube requires all of them at once. Note `Movies` plus a feature flag is usually over-constrained and returns very few rows.",
            "items": {
              "type": "string",
              "enum": [
                "hd",
                "4k",
                "subtitles",
                "creative_commons",
                "live",
                "360",
                "3d",
                "hdr",
                "vr180"
              ],
              "enumTitles": [
                "HD",
                "4K",
                "Subtitles / CC",
                "Creative Commons licence",
                "Live now",
                "360°",
                "3D",
                "HDR",
                "VR180"
              ]
            },
            "default": []
          },
          "rankBy": {
            "title": "📈 Prioritise results by",
            "enum": [
              "relevance",
              "view_count",
              "upload_date",
              "rating"
            ],
            "type": "string",
            "description": "YouTube's live Prioritise menu now contains only Relevance and View count. Upload date and Rating are still accepted and sent correctly, but YouTube ignores them — use the upload-date bucket or the exact date range instead. Leave empty to fall back to the legacy `sort_order` field.",
            "default": "relevance"
          },
          "publishedAfter": {
            "title": "📅 Published after",
            "type": "string",
            "description": "Absolute (`2024-03-01`) or relative (`3 months`, `2 weeks`). Videos published before this date are excluded by YouTube itself."
          },
          "publishedBefore": {
            "title": "📅 Published before",
            "type": "string",
            "description": "Absolute (`2024-03-31`) or relative (`1 week`). Videos published after this date are excluded by YouTube itself."
          },
          "minViews": {
            "title": "👀 Minimum views",
            "minimum": 0,
            "type": "integer",
            "description": "Drop videos below this exact view count. 0 = off.",
            "default": 0
          },
          "minLikes": {
            "title": "👍 Minimum likes",
            "minimum": 0,
            "type": "integer",
            "description": "Drop videos below this exact like count. Videos whose like count is not published are kept, not dropped. 0 = off.",
            "default": 0
          },
          "minDurationSeconds": {
            "title": "⏳ Minimum duration (seconds)",
            "minimum": 0,
            "type": "integer",
            "description": "Exact second-level floor, tighter than the coarse length band above. 0 = off.",
            "default": 0
          },
          "maxDurationSeconds": {
            "title": "⌛ Maximum duration (seconds)",
            "minimum": 0,
            "type": "integer",
            "description": "Exact second-level ceiling. 0 = off.",
            "default": 0
          },
          "titleContains": {
            "title": "🔤 Title must contain",
            "type": "array",
            "description": "Case-insensitive. A video is kept if its title contains at least one of these. Checked on the search card first, so non-matching videos are dropped before they cost a page fetch.",
            "items": {
              "type": "string"
            }
          },
          "titleExcludes": {
            "title": "🚫 Title must not contain",
            "type": "array",
            "description": "Case-insensitive. A video is dropped if its title contains any of these. Also checked on the search card first.",
            "items": {
              "type": "string"
            }
          },
          "max_comments": {
            "title": "💬 Comments per video",
            "minimum": 0,
            "maximum": 5000,
            "type": "integer",
            "description": "Top-level comments to attach to each matched video. Set 0 to skip comments entirely and run faster.",
            "default": 2
          },
          "include_transcripts": {
            "title": "📝 Attach transcripts",
            "type": "boolean",
            "description": "Fetch caption text when the video exposes it. Coverage measured at 86% of videos on a residential exit; near zero on datacenter, which is why the network defaults to residential.",
            "default": true
          },
          "transcript_format": {
            "title": "🧾 Transcript shape",
            "enum": [
              "text",
              "timestamps"
            ],
            "type": "string",
            "description": "Plain text is compact; timed segments keep the per-line timing.",
            "default": "text"
          },
          "include_english_auto": {
            "title": "🤖 Also take auto-generated English",
            "type": "boolean",
            "description": "Include YouTube's machine captions in English alongside creator-uploaded ones. Identical duplicate tracks are removed automatically.",
            "default": false
          },
          "include_non_english": {
            "title": "🌍 Also take other languages",
            "type": "boolean",
            "description": "Some videos expose 38+ language tracks, each a separate download. Use the language cap below to keep runs bounded.",
            "default": false
          },
          "maxTranscriptLanguages": {
            "title": "🔢 Transcript language cap",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Maximum caption tracks stored per video after duplicate removal. Protects row size — one measured transcript was over 500,000 characters.",
            "default": 5
          },
          "transcriptTimeoutSeconds": {
            "title": "⏲️ Transcript time budget (seconds)",
            "minimum": 10,
            "maximum": 600,
            "type": "integer",
            "description": "Per-video ceiling for caption downloading. When it is hit the video is still saved, just without transcripts.",
            "default": 120
          },
          "maxSearchPages": {
            "title": "📄 Max search pages per phrase",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Hard stop on YouTube search paging, so a rare filter cannot page forever. Each page yields roughly 7–20 filtered results.",
            "default": 30
          },
          "sort_order": {
            "title": "🗂️ Sort order (legacy field)",
            "enum": [
              "relevance",
              "upload_date",
              "view_count",
              "rating"
            ],
            "type": "string",
            "description": "Kept so input built for the standard YouTube Metadata Scraper still runs unchanged. `Prioritise results by` above takes precedence when you set it.",
            "default": "relevance"
          },
          "proxyConfiguration": {
            "title": "🌐 Proxy",
            "type": "object",
            "description": "Defaults to Apify Residential proxy in the United States, which is what YouTube requires here: 83% of datacenter watch-page fetches come back as HTTP 200 with an empty title and a login-required playability status, and caption downloads fail there entirely. Your selection is honoured; if it starts returning blocked pages the run escalates to residential and says so in the log.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ],
              "apifyProxyCountry": "US"
            }
          }
        }
      },
      "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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}