Blog/Developer Tools/

Bilibili Creator Research API Workflow | SandBase

Build a Bilibili creator-research workflow: read trends, search a topic, and profile the creator — one SandBase key, no Bilibili login.

Dark cinematic render of a Bilibili trend board resolving into search results and a creator profile feeding an agent core

Creator research on Bilibili comes down to three moves: see what is trending, search a topic for videos and creators, and profile the creator behind the content. This tutorial wires those three moves into one Bilibili creator research API workflow using the SandBase Bilibili API — no Bilibili login, no scraper. The endpoint API reference is the source of truth for each parameter and for the response envelope; the business-payload field names shown below are an illustrative shape, not a guaranteed schema, so confirm them against a live response for the endpoint you call.

If you want the full endpoint tour first, start with the Bilibili public data API hub. This piece is the applied workflow.

Key takeaway

  • Three steps: hot-search (trends) → search-all (topic) → user-profile (creator).
  • Every call is POST /v1/api/bilibili/<path> with one SANDBASE_API_KEY; responses share the { id, status, model, outputs } envelope.
  • Bilibili endpoints wrap their payload in an upstream { code, data, message } object, so the useful fields sit under data.data.
  • Public, read-only data only, with no posting on your side. No Bilibili login or OAuth is required for this public-data workflow; a SandBase API key is still required.

The workflow at a glance

StepEndpointInputYou get
1. Read trendsbilibili/web/hot-searchrequired limit (integer)a ranked list of trending keywords
2. Search the topicbilibili/app/search-allkeywordmatching videos and creators
3. Profile the creatorbilibili/web/user-profileuidname, level, signature

SandBase Bilibili endpoint reference showing the hot-search and creator endpoints used in this workflow The endpoint API reference is the source of truth for each parameter name and response path.

Start with a shared helper that branches on status and unwraps the upstream data, then read the hot-search board:

import os
import requests

BASE = "https://api.sandbase.ai/v1/api/bilibili"
HEADERS = {
    "Authorization": f"Bearer {os.environ['SANDBASE_API_KEY']}",
    "Content-Type": "application/json",
}


def call(path: str, payload: dict) -> dict:
    resp = requests.post(f"{BASE}/{path}", headers=HEADERS, json=payload, timeout=90)
    resp.raise_for_status()
    body = resp.json()
    if body.get("status") != "completed":
        raise RuntimeError(body.get("error", {}).get("message", "request did not complete"))
    # The reference guarantees only the envelope; business fields vary by
    # endpoint, so unwrap defensively and confirm against a live response.
    data = body["outputs"][0]["data"]
    # Bilibili wraps the payload in an upstream { code, data, message } object
    return data.get("data", {})


trending = call("web/hot-search", {"limit": 10}).get("trending", {}).get("list", [])
for item in trending[:5]:
    print(item.get("keyword"), item.get("heat_score"))

Each item carries a keyword and a heat score. The field names are not a guaranteed schema — confirm them against a live response, since the board changes constantly.

Step 2 — Search a topic

Pick a keyword and pull matching videos and creators. search-all takes a keyword and returns a list under data.item:

results = call("app/search-all", {"keyword": trending[0].get("keyword")})
# the reference guarantees only the envelope; business fields vary by
# endpoint, so use .get() and confirm against a live response
items = results.get("item", [])
# each item carries a goto/type, a uri, and author info;
# read the schema and inspect a real response to map the fields you need
print(len(items), "results")

The search-all response nests its list under data.item, with a pagination block for the next page. Inspect one real response to map where video ids and creator ids sit before you iterate.

SandBase Bilibili search-all API reference showing the keyword parameter and response schema search-all returns a list under data.item — read the schema before iterating.

Step 3 — Profile the creator

For a creator id (uid) you surface in step 2, attach account context. user-profile takes a uid:

creator = call("web/user-profile", {"uid": "946974"})
# the reference guarantees only the envelope; business fields vary by
# endpoint, so use .get() and confirm against a live response
print(creator.get("name"), creator.get("level"))

The profile read returns fields like name, level, sign, and sex. The block below is an illustrative response shape — the field names are not a guaranteed schema, so treat them and the values as examples and confirm them against a live response:

{
  "id": "cbc4c9c1-84e7-4ea6-9e3f-f5e759c11475",
  "status": "completed",
  "model": "bilibili/web/user-profile",
  "outputs": [
    {
      "data": {
        "code": 0,
        "data": { "mid": "946974", "name": "…", "level": 6, "sign": "…" }
      }
    }
  ]
}

Note the double nesting: outputs[0].data is the SandBase envelope payload, and the useful profile sits under its inner data. The call helper above already unwraps one level for you.

SandBase Bilibili user-profile API reference showing the uid parameter and response schema user-profile returns name, level, and signature under the upstream data object.

Putting it together

A minimal creator-research pass looks like this:

# the reference guarantees only the envelope; business fields vary by
# endpoint, so use .get() and confirm against a live response
trending = call("web/hot-search", {"limit": 10}).get("trending", {}).get("list", [])
report = []

for topic in trending[:10]:
    hits = call("app/search-all", {"keyword": topic.get("keyword")})
    report.append({
        "topic": topic.get("keyword"),
        "heat": topic.get("heat_score"),
        "result_count": len(hits.get("item", [])),
    })
    # for creator uids you extract from hits, call user-profile per the schema

Because every call shares the same envelope and the same call helper (including the data.data unwrap), adding retries or rate-limit backoff is a one-place change. When you need more than these reads, check the live Bilibili listing for the endpoint that fits and confirm its parameters before wiring it in.

Handling the rough edges

  • Mind the double nesting. Bilibili passes through an upstream { code, data, message } object, so the useful payload sits under data.data. Unwrap it once in your helper.
  • Inspect search-all before iterating. Its list sits under data.item and is structured, not flat — map the fields from a real response and page via its pagination block.
  • Branch on status. A failed or timeout run carries error and no outputs. The call helper already enforces this.
  • Respect rate limits. As a client-side resilience measure, retry with backoff on transient errors such as HTTP 429.
  • Public data only. No login, posting, or private/account-only content.

Composing the workflow

The same uniform envelope keeps this composable. Swap the trending keyword for any topic, add a fourth read — a video’s comments, say — and it slots in behind the same call helper with the same status check and unwrap. You can also fan the middle step out: for each of the top N trending keywords, run search-all and collect the counts into one table, so a single pass gives you a ranked snapshot of what is trending and how much content each topic carries. Because the reads share one shape, moving from a quick script to a scheduled job is mostly a matter of adding backoff and a place to store each pass.

Why run this at the API layer

You could open Bilibili in a browser and copy numbers by hand, but that does not scale and it does not give you structured data to trend. Running these three calls on a schedule turns qualitative browsing into a measurable signal: heat scores you can chart over time, topics you can dedupe, and creators you can weight by level and following. Because the calls return named JSON fields behind one consistent unwrap, each pass drops cleanly into a table you can diff against the last one — new trending topics, new creators surfacing on a keyword, and shifts in what the platform is watching.

FAQ

Do I need a Bilibili login or OAuth? No. You authenticate to SandBase with your SANDBASE_API_KEY, and these three reads need no Bilibili account or OAuth on your side. You still supply a SandBase API key to call them.

Why does hot-search need a limit and why unwrap data.data? hot-search takes a limit parameter for how many trending items to return, so pass it explicitly. And because Bilibili passes through an upstream { code, data, message } object, the useful payload sits under data.data — unwrap that one level in your call helper. Confirm both against the endpoint reference.

How do I page through search-all results? Pass the pagination request parameter that search-all accepts on its next call rather than assuming a fixed page size. Check the endpoint reference for the exact parameter name and confirm it against a real response before you loop.

Next steps

You now have a repeatable creator-research workflow built on three public, read-only calls.