{
  "openapi": "3.0.1",
  "info": {
    "title": "Bilibili Scraper — Videos, Danmaku, Comments & Creator Search",
    "description": "Scrape Bilibili (哔哩哔哩), China social media for video: search, video details, comment threads, Chinese influencer uploads and the popular board — plus danmaku (弹幕), the scrolling on-video reactions no other platform has, no cookie needed. Delta mode bills only what is new.",
    "version": "1.3",
    "x-build-id": "5WblcxabdpM0RPUPT"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/zhorex~bilibili-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-zhorex-bilibili-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/zhorex~bilibili-scraper/runs": {
      "post": {
        "operationId": "runs-sync-zhorex-bilibili-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/zhorex~bilibili-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-zhorex-bilibili-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": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "video_detail",
              "video_comments",
              "user_videos",
              "popular"
            ],
            "type": "string",
            "description": "What to scrape from Bilibili",
            "default": "search"
          },
          "searchQuery": {
            "title": "Search query",
            "type": "string",
            "description": "Search query — works in Chinese (人工智能) and English (AI tutorial). Used in 'search' mode."
          },
          "autoLocalize": {
            "title": "Auto-localize brand names (search mode)",
            "type": "boolean",
            "description": "When on, a Latin brand name (e.g. 'Nike') also searches its Chinese name ('耐克') and results are merged — so you get full native recall even when searching in English. Capped at maxResults (no extra cost). Add your own variants via Search aliases below.",
            "default": true
          },
          "searchAliases": {
            "title": "Search aliases (search mode)",
            "type": "array",
            "description": "Extra term variants to also search and merge with your query — e.g. add '耐克' for Nike, or alternate spellings. Useful for brands not in the built-in dictionary.",
            "items": {
              "type": "string"
            }
          },
          "sortOrder": {
            "title": "Sort order (search mode)",
            "enum": [
              "totalrank",
              "click",
              "pubdate",
              "dm",
              "stow",
              "scores"
            ],
            "type": "string",
            "description": "How to sort search results. Used in 'search' mode.",
            "default": "totalrank"
          },
          "durationFilter": {
            "title": "Duration filter (search mode)",
            "enum": [
              "any",
              "short",
              "medium",
              "long",
              "verylong"
            ],
            "type": "string",
            "description": "Filter search results by video duration. Used in 'search' mode.",
            "default": "any"
          },
          "pubtimeBegin": {
            "title": "Published after (search mode)",
            "type": "string",
            "description": "Filter videos published after this date (YYYY-MM-DD). Leave empty for no filter. Used in 'search' mode."
          },
          "pubtimeEnd": {
            "title": "Published before (search mode)",
            "type": "string",
            "description": "Filter videos published before this date (YYYY-MM-DD). Leave empty for no filter. Used in 'search' mode."
          },
          "deltaMode": {
            "title": "Delta mode — only NEW videos since last run (search + popular)",
            "type": "boolean",
            "description": "Turn a one-off pull into a recurring monitor: when on, each run returns only videos not seen in previous runs (deduped by video ID across runs, per Delta state key). Pair it with an Apify Schedule for a hands-off daily/weekly 'what's new' feed — you pay only for genuinely new videos. Works in 'search' mode (new videos for your keyword) and 'popular' mode (new videos trending now that weren't before). Tip: in search mode set Sort order to 'Newest first' for monitoring. <b>Know the trade before you switch it on:</b> a full run returns the whole current result set and bills for it; a delta run returns only what has appeared since the last run. On fast-moving boards (trending, hot search, popular) that is still a healthy batch every run. On a narrow keyword or a single creator it can be a handful of rows, or none on a quiet day — which is the feature working, not a broken run. Pick delta when you want to be told what is NEW; leave it off when you want the data itself.",
            "default": false
          },
          "deltaStateKey": {
            "title": "Delta state key (search + popular mode)",
            "type": "string",
            "description": "Names the saved 'already-seen' state so independent monitors don't collide. Use a distinct key per query/category you track (e.g. 'nike-weekly', 'game-trending'). Only used when Delta mode is on.",
            "default": "default"
          },
          "videoUrls": {
            "title": "Video URLs or BVIDs",
            "type": "array",
            "description": "Bilibili video URLs or BV IDs. Used in 'video_detail' and 'video_comments' modes. Example: https://www.bilibili.com/video/BV1xx411c7mD or BV1xx411c7mD",
            "items": {
              "type": "string"
            }
          },
          "userIds": {
            "title": "User IDs (mid)",
            "type": "array",
            "description": "Bilibili user numeric IDs (mid). Used in 'user_videos' mode. Find a user's mid in their profile URL: space.bilibili.com/{mid}. <b>How this mode works, so the row count is not a surprise:</b> Bilibili's direct space listing is behind risk control that rejects plain HTTP requests, so the Actor searches the creator's channel name and keeps the videos whose mid matches. That reliably returns about the 20 most recent, and fewer when the creator's name is common. For a wider sweep use 'search' mode with the creator's name.",
            "items": {
              "type": "string"
            }
          },
          "category": {
            "title": "Category for popular/trending",
            "enum": [
              "all",
              "animation",
              "music",
              "dance",
              "game",
              "knowledge",
              "tech",
              "sports",
              "car",
              "life",
              "food",
              "animal",
              "fashion",
              "entertainment"
            ],
            "type": "string",
            "description": "Filter popular videos by category. Used in 'popular' mode.",
            "default": "all"
          },
          "maxResults": {
            "title": "Max results (raise for bulk monitoring)",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "Maximum number of results to scrape. Typical patterns: 20-50 for a quick lookup, 100-300 for daily creator / category monitoring, 500 for a full keyword sweep or content-analytics pull. Higher values automatically walk more result pages. See the Pricing tab for per-result cost.",
            "default": 100
          },
          "includeComments": {
            "title": "Also scrape comments for each video",
            "type": "boolean",
            "description": "In <b>search</b>, <b>user videos</b> and <b>popular</b> modes, also pull the comment thread of every video found and return each comment as its own row (<code>type: comment</code>, with <code>likeCount</code>, <code>replyCount</code> and author). Comments are where the audience opinion is — the video is the prompt, the replies are the sentiment. No login or cookie needed. Cap it with <b>Max comments per video</b>, and note that <b>this multiplies the rows a run returns, and therefore what it costs</b>: 100 videos × 20 comments is ~2,100 rows instead of 100. Off by default.",
            "default": false
          },
          "includeReplies": {
            "title": "Expand comment threads (reply chains)",
            "type": "boolean",
            "description": "Bilibili serves an anonymous caller only <b>1-3 top-level comments</b> per video, which is not a thread. Turn this on and every reply becomes its own row, tagged with <code>rootRpid</code> and <code>isThreadReply</code> so you can rebuild the conversation. The flag reads the replies Bilibili inlines in the same response AND pages any further ones the root declares in <code>replyCount</code>, one request per thread, stopping as soon as your <code>maxComments</code> is met. <b>Be realistic about how much this adds, measured on Apify itself 2026-08-25:</b> across 6 trending videos the 18 root comments served anonymously declared <b>1 reply between them all</b>, so the flag added exactly 1 row. Roots reached from a residential IP have been seen declaring far more (61 across 14 videos on 2026-08-15), so the upside is real but it depends on where you run from, and on Apify's datacenter range it is usually close to zero. It costs nothing when there is nothing to fetch: with no declared replies it makes no extra requests at all. <b>Caveats:</b> replies bill as ordinary comment rows; and roughly 4 in 10 videos return no comments at all anonymously. Off by default.",
            "default": false
          },
          "includeDanmaku": {
            "title": "Add a danmaku profile per video (no cookie needed)",
            "type": "boolean",
            "description": "Danmaku (弹幕) is Bilibili's on-video scrolling commentary — comment text bound to a specific <b>second</b> of the video, which no other platform has. With this on, each video also returns one <code>type: danmaku</code> row with <code>danmakuFetched</code>, <code>danmakuUniqueSenders</code>, <code>danmakuPerMinute</code>, the <b>peak minute</b> and its count, first/last timestamps, and an evenly-spread text sample across the whole video. <b>What it is for:</b> second-by-second audience reaction on an ad or a launch, and creator vetting — danmaku-per-minute beats view count as an engagement signal because a danmaku costs the viewer effort. Measured: a single video carries ~3,000 danmaku (3,415 on one test). <b>Cost is predictable:</b> this adds ONE row per video, not one per danmaku. Off by default. <b>Billing:</b> each danmaku row is its own <code>danmaku-profile</code> event at <b>$0.05</b> — 2.5x a normal $0.02 row — because it fetches and reduces ~3,000 danmaku per video. Profiling 200 videos costs $10. Off by default.",
            "default": false
          },
          "danmakuSampleSize": {
            "title": "Danmaku text samples per video",
            "minimum": 0,
            "maximum": 500,
            "type": "integer",
            "description": "How many danmaku texts to include in the sample, spread evenly across the video timeline (not the first N, which would all come from the opening seconds). The sample rides inside the single danmaku row, so raising it does not add billable rows.",
            "default": 25
          },
          "maxComments": {
            "title": "Max comments per video",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Maximum number of comments to scrape per video. Used in 'video_comments' mode.",
            "default": 20
          },
          "sortComments": {
            "title": "Sort comments by",
            "enum": [
              "hot",
              "time",
              "likes"
            ],
            "type": "string",
            "description": "How to sort comments. Used in 'video_comments' mode.",
            "default": "hot"
          },
          "sentimentAnalysis": {
            "title": "Sentiment analysis",
            "type": "boolean",
            "description": "Tag each item with lexicon-based Chinese sentiment — polarity + a -1.0…+1.0 score (comments + video titles/descriptions). Optional add-on — for Chinese text it loads a model, so enable with run memory set to 512 MB or more.",
            "default": false
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}