Bilibili scraper API, no login: video comments, replies, danmaku (弹幕), search videos, video details, user profiles, creator videos, followings, popular & hot videos, weekly must-watch, precious, ranking, hot search (热搜), live rooms from B站/哔哩哔哩 as JSON. Lean AI-agent output, dry run. $0.005/video.
2.1.0 – 2026-10-16 (search depth past the 1,000-result cap; same prices, events, inputs, listing and default output)
Search past Bilibili's ~1,000 results per query: when a query's 20 pages are exhausted and maxItemsPerInput/maxItems ask for more (up to 5,000 per keyword), the Actor sweeps publish-date windows newest first inside dateFrom/dateTo (a window that is itself capped is split down to 1 day before its pages are read; sparse windows widen up to 1 year). Same order and filters; duplicates are skipped free; the summary notes say how many windows/requests the sweep used. Locally 原神 1,300 videos: 1,300 distinct in 30 requests, 21 s (2.0.3 stopped at ~964–1,021 distinct).
Capabilities limits.searchDepth documents the sweep.
Docs: the 2.0.2–2.0.3 fix line above is now dated and shipped in a build (it was only in the source).
2.0.0 – 2026-10-15 (research workflow, trust fields, snapshots, insights; same prices, events and default output; builds 2.0.1–2.0.5, live 2.0.3 GaETkx5obJTZbDFjO)
New operation keywordComments (aliases keyword_comments, comment_research): keyword → top maxVideos videos (sortBy, dateFrom/dateTo, minViews, durationFilter, expandQuery) → commentsPerItem comments (commentSort hot|newest) → replies (replyDepth 0|1, repliesPerComment) → free insights row per keyword. matchTerms keeps matching top-level comments/danmaku (filters after fetching). Without keywords but with urls it runs comments on them (routing bug in the unreleased v2 draft fixed: it ran videoDetails).
Trust fields on every row:isPartial, unavailableFields[], collectionWarnings[]; summary adds requested, perInput[] (returned per input, status), pagesFetched, isPartial.
Computed video metrics:likesPer1kViews, commentsPer1kViews, engagementRate, danmakuPerMinute, detailLevel (formulas in capabilities.computedMetrics).
Free insights row (include: ["insights"], default on for keywordComments): top terms (CJK bigrams merged into trigrams when the trigram explains every use, e.g. 评论区 instead of 论区), emotes, matchTerms counts, most-liked comments, top videos, heuristic lexicon sentiment (no LLM), danmaku peak minute and a per-video danmaku profile (timelinePerMinute, peakMinute, poolFetched vs returned, uniqueSenders with include author).
Billing map ready for a later price change: each row type maps to a chain of event names (video-basic/video-enriched → result); the first event that exists in the live pricing is charged, so today every video row is still result ($0.005). No price or event changed.
Fix (2.0.2–2.0.3, 2026-10-15): keywordComments with only urls now keeps its own defaults when it falls back to comments (commentsPerItem as the per-video limit, default 10; insights row on; replies on with 2 per comment). It returned 20 comments and no insights row in 2.0.1.
New input fields: maxVideos, commentsPerItem, replyDepth, repliesPerComment, commentSort, insights, trackMetrics, matchTerms. All v1.x inputs and the compact default output keep working (new fields are only added).
1.4.0 – 2026-10-13 (agent-native polish; same prices, events, inputs and default output)
Copy-paste example input for every operation: README "For AI agents" table and exampleInput on each operation of the free capabilities row (same list, unit-tested against the input schema).
Accurate texts: include: details costs 1 batched request per 50 videos in compact/lean mode (was documented as 1 per video); the 512 MB hint for big full-mode runs states the measured 1.7–2.9× speed-up; README speed line uses platform numbers.
Store listing (title "Bilibili Comments & Danmaku Scraper API, No Login – B站 哔哩哔哩", description listing the data types agents search for: video comments, replies, danmaku, search videos, video details, user profiles, creator videos, followings, popular & hot videos, weekly must-watch, precious, ranking, hot search, live rooms). Two listing loops; the Store search index refreshes after a build (docs-only builds 1.4.1–1.4.3, 1.4.5). A revert to the v1.3 loop-2 listing (build 1.4.4) measured worse than the loop-2 listing under the refreshed index, so the loop-2 listing was restored.
1.3.0 – 2026-10-13 (live build 1.3.4 iMHCt1JnAiW8EpLfH; limits removed where public, faster heavy runs; same prices and events; v1.2 inputs and default output unchanged)
New operation followings (关注列表): the accounts a creator follows, from Bilibili's public app endpoint (the web endpoint needs a login). User rows billed as profile, with new keys followingOf and followedAt. Bilibili shows logged-out visitors the newest 250 (5 pages × 50); creators who hide the list get a NO_RESULTS row that says so.
Ranking fallback rows complete: when the web ranking is risk-controlled, coins, shares, description, width, height and partsCount are filled from the public batch video-info endpoint (2 requests per 100 rows); the summary note names all six fields and how many rows were filled.
trend.isCommercial works (was always null): the hotword list (same keywords, same order) is read in parallel and its commercial flag merged.
include: details in compact/lean mode is batched: 1 request per 50 videos instead of one view call per video (field-identical on a 50-video check). Heavy compact run (300 videos + details/owner/topComments) 106 s → 69 s, −35 % CU, side by side (37.5 s in the release regression).
Full mode writes its own dataset batches (serialised once, uncompressed, ≤ 8 MB per request, SDK fallback): −12 % to −48 % time/CU on the 300-row full case in two side-by-side runs (1.3.1: 212 vs 242 s; 1.3.4: 110 vs 210 s); heavy runs vary ±40 % run to run. Most full-mode bytes are Bilibili's collection list (ugc_season), which is part of the raw record; the summary now suggests 512 MB for big full runs (measured 72 s vs 105–212 s at 256 MB; CU 0.0100 vs 0.0077–0.0147).
Listing/README: one README section per operation named with the words agents search for (video comments, danmaku, search videos, video details, user profile, creator videos, followings, popular videos, weekly/precious, ranking, hot search, live rooms); input field titles name the operations they feed.
Summary timingsMs.cpu (process CPU ms). Capabilities notAvailable lists the login-only data re-checked on 2026-10-13 (subtitles, fan lists, commenter IP region, danmaku history).
1.2.0 – 2026-10-13 (token-efficient output, verified data, weekly/ranking fixes; same prices and events; all v1.1 inputs and default output unchanged; builds 1.2.1–1.2.6, live 1.2.6 ER1Q5MN9OBfIMLlA2)
Heavy full-mode runs (1.2.6):outputMode: "full" writes rows in batches of 25 (was 200) and runs at most 8 requests in parallel (was 16); 300 full rows with details+owner+topComments 187 s → 168 s, −10 % CU, −19 % peak memory vs 1.2.5 in a side-by-side run.
New outputMode: "lean" (opt-in): type + id + curated fields per row kind, null/empty/false omitted, envelope (operation, input, queryUsed, fetchedAt) once in the summary row, url derivable from id (patterns in the summary and capabilities), text cut to maxTextChars (default 300, truncated: true), dates YYYY-MM-DDTHH:MMZ UTC. Lean also skips enrichment requests its fields do not need (e.g. tags). Measured: −64 to −84 % tokens per row (median −77 %); table −71 to −90 % (median −83 %). leanFormat: "table" adds one TSV block per row kind (header once) to the summary row and key-value record LEAN_TABLE; rows are still pushed and billed the same. New input maxTextChars (any mode).
Weekly (每周必看) fixed: the web endpoint answers -352 to most guest IPs; the Actor now reads the app weekly list (order, recommend reason, config.media_id) and the issue's public media list (full stats), with the web endpoint as fallback.
Ranking fixed: when the web ranking answers -352 the app ranking (separate risk control) is used at once instead of ~20 s of retries that ended FAILED. rankingCategory also accepts names (gaming, music, tech, …).
New operation precious (入站必刷, ~100 all-time must-watch videos, full stats).
Competitor parity:deltaKey monitoring mode (only rows not returned before; skipped rows free), allParts for danmaku of multi-part videos, danmakuSource: "segments" (XML pool + 6-minute protobuf segments, deduplicated: e.g. 2,943 vs 1,200 rows on one part), userVideos with sortBy: "views".
Data fixes (field audit against independent sources):categoryName was null on videoDetails/userVideos rows (Bilibili stopped sending tname) → v1 zone name table; categoryId is now the v1 zone id on every operation (videoDetails used tid_v2); creator uploads stopped at 100 with a NOT_FOUND row (page size 100 + cursor = -400) → page size 50 after the first page; articlesCount was always 0 (card) → creator navnum (only requested when the field is wanted); BGM pseudo-tags ("发现《…》") and duplicate tags removed; width/height swapped for rotated (portrait) uploads; isOriginal documented (copyright 3 = not declared → null).
Faster start: source bundled into one file with esbuild at build time (in-process startup ~0.45–1.1 s → ~0.3 s); up to 16 requests in parallel (adaptive backoff unchanged; tag-heavy runs ~30 % faster).
Dry run:estimatedRows, estimatedSeconds, realistic caps for weekly/precious/ranking/danmaku. Summary nextSteps suggests lean mode on big compact runs.
1.1.0 – 2026-10-13 (efficiency + discoverability; same inputs, outputs and prices; builds 1.1.1–1.1.7, live 1.1.7 zKvLPo3k6Is1d0Gg8)
Faster: default calls ~2–4 s (were 3–8 s); 200 search results 43 s → ~4 s; 50 trending videos 27 s → ~4.5 s; 200 comments 24 s → ~5 s; 200 danmaku 21 s → ~2 s.
Batched output: rows are written and charged in batches (Actor.pushData(rows, event)), in the background while the next page loads, instead of two API calls per row. Same per-row prices and chargedEventCounts.
Scope efficiency:fields[] now also limits requests. Tags, ownerFollowers, topComments and view-only stats are fetched only when their field is requested (popular 50 with fields:["title","views"] = 1 request instead of 51). Search rows reuse their own tags with include: ["details"].
Fewer requests per page: search up to 50 results per request, popular 50, creator uploads 100, comments 30 (were 20/20/20/20); danmaku resolves the part id with the small pagelist call instead of the full video view; one shared WBI key fetch.
No guest-session setup on the default path: search, video view, popular and tags go cookie-less first (the guest cookie session is now the fallback), saving 4 requests at start.
Parallel requests: up to 8 in flight (was 4, serialised by a 250 ms global delay). requestDelayMs default 250 → 0; the Actor raises the delay to 250 ms and halves parallelism automatically after the first rate-limit / risk-control answer.
HTTP: Node's built-in fetch (keep-alive, gzip/br) for direct requests; got-scraping is only loaded when a proxy is used. The Apify proxy is set up lazily (only after a block).
Lighter runtime:apify/actor-node:22-slim base, npm ci, node started directly (no npm wrapper), V8 heap capped at 75 % of run memory. Peak memory ~70 MB → ~35–45 MB. Default run memory 512 → 256 MB (minMemoryMbytes 128).
Safety: run deadline stops new work 20 s before the run timeout (partial rows + summary instead of TIMED-OUT). Summary row adds timingsMs (startup, first row, total).
include comments: each video's first comment page is prefetched in parallel (rows still come video by video), and one write batch can mix videos and comments: 40 trending videos + 5 comments each ~6 s locally (was one request after another).
Filters before enrichment:minViews / minLikes / dates / dedupe are checked on list data before any per-video request; rows that cannot be afforded under maxItems / maxCostUsd are not enriched.
Fixes: summary billedEvents / chargedUsd now read the SDK's charge counter (the batched charge result could be counted twice on the platform; the platform's chargedEventCounts was always right). Ranking fallback is now WBI-signed cookie-less (the guest-session call gets -352). Hard watchdog on every HTTP request (one platform run stalled with requests in flight). topComments fetch uses a 5-comment page.
Store text: title, description, SEO title/description and README headings now lead with "Bilibili comments", "Bilibili danmaku" and "videos" (the phrases agents search).
1.0.0 – 2026-10-12 (agent-native rebuild; final build 1.0.6, ID R3sGPtSeKhY0rwgDf)
14 operations in one Actor (operation, default auto): search, videoDetails, comments, replies, danmaku, related, userProfile, userVideos, searchUsers, popular, weekly, ranking, hotSearch, liveRoom, plus free capabilities. New inputs users[] and ids[] (auto-routed by shape: BV…:commentId, mid:…, space/live links).
English→Chinese query expansion (expandQuery, default on): shared curated dictionary work/actors/_shared/query_expansion/en_zh.json (~940 entries), copied to src/data/en_zh.json (npm run sync-dict); keywords ≤2 chars stay literal; Chinese searched first, original fills the shortfall; rows show queryUsed.
Output contract: every row starts type, operation, input, queryUsed, id, url, fetchedAt, rank; kinds video / comment / danmaku / user / trend / liveRoom; free error rows (errorCode, errorMessage, suggestedFix; new codes NOT_SUPPORTED, INTERNAL_ERROR), free summary row last (counts, billedEvents, chargedUsd, stopReason, warnings, nextSteps), plan, capabilities. Output field mode → operation, scrapedAt → fetchedAt (breaking for v0.x output consumers); bvid now canonical (derived from aid).
Pricing: new PPE events comment $0.001, danmaku $0.0001, profile $0.003 (creator or live room), trend $0.001; result $0.005/video and apify-actor-start unchanged. Submitted 2026-10-12 22:58 IST via API; no paying users, so effective immediately (no 14-day notice needed).
Endpoints: cookie-less WBI comments (/x/v2/reply/wbi/main, 20/page, paginated – guest cookies cap comments at 3), replies (/x/v2/reply/reply), danmaku XML (/x/v1/dm/list.so), related, user card, medialist uploads (space arc search is 412/-352 for guests), user search, hot search (search/square, fallback hotword), live rooms; weekly now WBI-signed (unsigned gets -352); offline BV↔AV conversion.
Input schema rewritten (28 fields, 20 most important first, every enum value explained, ≤500 chars, prefill keywords: ["原神"]), dataset schema with all kinds (no required keys, nullable types) + views per kind, output schema results + runSummary. Store title/description/SEO rewritten; README "For AI agents" section.
Backward compatible inputs: mode (wins over the injected operation: auto default), searchKeywords, videoUrls, searchOrder, searchDuration, fetchDetails, includeComments, includeTags, maxCommentsPerVideo, includeCommentAuthor, legacy per-keyword maxItems.
Every input optional (mode auto – Bilibili: added auto, no longer required; explicit modes still work); misplaced inputs auto-corrected (site URL in keywords → fetched, plain word in urls → searched); explicit mode with missing input falls back to the given input.
Out-of-range numbers clamped instead of rejected (schema max/min removed; ranges in descriptions) – agents don't see schema min/max.
New type: "error" dataset rows with errorCode / errorMessage / suggestedFix (never billed); input, not-found and no-result problems now end SUCCEEDED with these rows; status message lists codes + first fix; RUN_SUMMARY has errorRows, notes.
Inputs renamed to arrays agents use:keywords[] (was searchKeywords) and urls[] (was videoUrls); old names still accepted as aliases.
mode is required with no default (MCP marks it REQUIRED); prefill examples for mode, keywords, urls, maxItems.
Default maxItems 50 → 10; in search mode it now applies per keyword.
Output: every item has the same 36 keys in every mode (null / [] when not available); dataset schema now has title, description and example per field and validates the real output.
Added .actor/output_schema.json (videos dataset + RUN_SUMMARY record), required for Store publishing and shown to agents.
Speed: videos enriched 4 at a time with a race-safe rate limiter; optional session steps (bili_ticket, buvid activation) run in parallel with 8 s timeouts; request timeout 30 → 15 s; requests go direct first and switch to Apify Proxy on the first block (custom proxy / proxy group = always proxy). Default 10-video runs went from 15–58 s to ~5–9 s on the platform.
Status messages: progress during the run and a final "Finished: N videos scraped (mode). K input(s) skipped (not billed)"; invalid input fails fast with an example in the message.
Actor default run memory 4096 → 512 MB (defaultMemoryMbytes + Actor defaultRunOptions).
PPE events unchanged: actor-start (charged only if configured; Apify's synthetic apify-actor-start also works) + result per video.
0.1.0 – 2026-10-12
First release.
Modes: keyword video search, video details (URL / BV / av / b23.tv), popular/trending (热门), weekly must-watch (每周必看), category Top-100 ranking (排行榜, 2025+ category ids).
Optional top public comments (guest limit ≈3 per video), commenter names off by default.
WBI signing (w_rid/wts), guest cookies (buvid3/buvid4/b_nut/_uuid), buvid activation and bili_ticket to avoid search captchas; fallback to combined search for page 1.
Retries with exponential backoff and session/proxy rotation on -352/-412/v_voucher; request throttling.
Pay-per-event charging: actor-start + result per video, stops at the run's max charge.
Dataset schema with Videos / Full details / Top comments views.