{
  "openapi": "3.0.1",
  "info": {
    "title": "YouTube Comments Scraper — Replies, Likes & Channel Videos",
    "description": "Paste YouTube video, Shorts or channel links and get the comments as rows: text, author, likes, reply count, pinned and creator-heart flags, plus the replies underneath at the same price. Top or newest order, exact per-video limit, no start fee. Comments off is an uncharged row, never a charge.",
    "version": "1.0",
    "x-build-id": "EXgodDWhTyMomixiy"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/steadyfetch~youtube-comments-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-steadyfetch-youtube-comments-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/steadyfetch~youtube-comments-scraper/runs": {
      "post": {
        "operationId": "runs-sync-steadyfetch-youtube-comments-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/steadyfetch~youtube-comments-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-steadyfetch-youtube-comments-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",
        "required": [
          "videoUrls"
        ],
        "properties": {
          "videoUrls": {
            "title": "Video URLs",
            "type": "array",
            "description": "YouTube video links or ids, one per line: https://www.youtube.com/watch?v=<id>, youtu.be/<id> (a ?si= tracking tail is fine), /shorts/<id>, /live/<id>, /embed/<id>, /v/<id>, or the bare 11-character id. Each one is read once for its comment page and then walked under the order and the per-video limit set below. A playlist link is refused on an uncharged row naming the field, because a playlist is not a video. Leave this empty and the run returns a small built-in sample from one public video instead of collecting anything, at no result fee.",
            "default": [
              "_demo"
            ],
            "items": {
              "type": "string"
            }
          },
          "channels": {
            "title": "Channels",
            "type": "array",
            "description": "YouTube channels, one per line — @handle, https://www.youtube.com/@handle, /channel/UC…, /c/… or /user/… . The newest uploads of each channel (\"Videos per channel\" below) are taken in turn and their comments delivered with the same columns, so you never have to paste video links yourself. A channel that does not exist, or a link that is not a channel, ships one uncharged row saying so; a channel that lists no public videos ships one too.",
            "items": {
              "type": "string"
            }
          },
          "startUrls": {
            "title": "Start URLs (video and channel links mixed)",
            "type": "array",
            "description": "One list for every kind of YouTube link, for buyers moving over from another scraper: video links, Shorts links and channel links together. Each line is sorted into the right door by its own shape before anything is read, so a channel link never gets asked for as a video and a video link never triggers a channel listing. A playlist or a community-post link is refused on an uncharged row naming this field.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "sort": {
            "title": "Comment order",
            "type": "string",
            "description": "top (default) is YouTube's own \"Top comments\" order — the pinned comment first, then by engagement. newest is \"Newest first\". They are different feeds: Top stops serving pages at roughly 1,200 comments on the videos we measured, while Newest kept going past 3,000, so newest is the order to ask for when you want depth. Anything other than top or newest is refused, uncharged, naming both values.",
            "default": "top"
          },
          "includeReplies": {
            "title": "Include replies",
            "type": "boolean",
            "description": "ON (default): the replies under each comment are delivered too, each as its own row with isReply: true and the parentCommentId it answers, so a thread can be rebuilt exactly. A reply is charged as a comment — the same event and the same price, never a second or a separate purchase — and replies count against \"Max comments per video\" like any other row. OFF: top-level comments only.",
            "default": true
          },
          "resultsLimit": {
            "title": "Max comments per video",
            "type": "integer",
            "description": "How many comment rows to take from EACH video — exact, never overshot and never padded, and replies count toward it. Delivered equals charged: a video that holds fewer gives you what it holds and the run says so. ⚠ YouTube itself ends the comment feed at some depth — measured at about 1,200 on top order and beyond 3,000 on newest — and a run that reaches that end ships one uncharged row naming the count it stopped at and the order that goes deeper. Other scrapers call this maxComments (the biggest listing's own name for it, where it defaults to 1), commentsPerVideo, limit or count; every one of those names is read as THIS field — the per-video one — and the smallest of them wins, with one uncharged note row saying which was read. Accepted range 1 to 5,000; a number outside it is moved to the nearest value in range and one uncharged note row says so, rather than the run being refused before it starts.",
            "default": 100
          },
          "maxItems": {
            "title": "Max rows to return",
            "type": "integer",
            "description": "Hard ceiling for the WHOLE run, counting comments and replies together across every video and every channel, whatever else is set. The per-video cap is \"Max comments per video\" above. ⚠ maxComments, commentsPerVideo, limit and count are NOT read as this field: on the listings that use those names they mean the PER-VIDEO limit, so they are folded onto \"Max comments per video\" above and a note row says so. This box is the run-wide ceiling and has to be set by its own name. Accepted range 1 to 100,000; a number outside it is moved to the nearest value in range.",
            "default": 1000
          },
          "videosPerChannel": {
            "title": "Videos per channel",
            "type": "integer",
            "description": "How many of each channel's NEWEST uploads to take comments from. Read only by the \"Channels\" box and by channel links in \"Start URLs\"; a video you named yourself ignores it. Each of those videos then gets its own \"Max comments per video\" share, so 5 videos at 100 comments is an ask of 500 rows. Accepted range 1 to 50; a number outside it is moved to the nearest value in range and one uncharged note row says so.",
            "default": 5
          },
          "maxRunSeconds": {
            "title": "Max run seconds",
            "type": "integer",
            "description": "The run stops cleanly before this many seconds and reports what is left, instead of being killed by a timeout. A time limit ends the collecting, never the delivering: rows already in hand are always written out. Accepted range 30 to 3,600 seconds; a number outside it is moved to the nearest value in range and one uncharged note row says so.",
            "default": 600
          },
          "includeSeen": {
            "title": "Include comments you already have",
            "type": "boolean",
            "description": "OFF (default): a comment already delivered to your account is skipped — no row, no charge. ON: those comments are delivered again anyway, marked repeat: true, and still not charged. Anything older than 90 days in your account's memory counts as new again either way.",
            "default": false
          },
          "resumeFromDatasetId": {
            "title": "Skip comments in this dataset",
            "type": "string",
            "description": "The dataset ID of a previous run of this actor. Comments already in it are treated as rows you already have and are skipped, so a follow-up run collects only what is new even from a different Apify account. Selecting it here is what grants this run permission to read it."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}