Douyin User Search API: Python & cURL Creator Search (2026)
Douyin user search API tutorial: find creators by keyword with the SandBase Model API in cURL and Python, with a dated live test and pagination notes.

Douyin User Search API: Find Creators by Keyword
Key takeaway —
douyin/search/user-search-v2searches public Douyin creator accounts by keyword throughPOST /v1/api/douyin/search/user-search-v2, with onlykeywordandcursorin the body. In the 2026-10-01 tests each page returned 30 accounts, and pages can overlap, so followcursorwhilehas_moreis true and deduplicate byuser_id. The catalog listed the endpoint as Free as of 2026-10-01.
Need to find Douyin creators in a specific niche? Whether you’re building a KOL discovery tool, monitoring competitors, or automating social media research, the Douyin User Search API through SandBase lets you search public Douyin creator accounts by keyword from your own code.
In this tutorial, you’ll learn how to call the endpoint, parse the response, and integrate it into real workflows, with curl and Python examples tested on 2026-10-01 (UTC).
Why Search Douyin Users by API?
Douyin (the Chinese counterpart of TikTok) has a very large creator base, and manually searching for creators through the app is tedious and doesn’t scale. An API-based approach lets you:
- Discover KOLs (Key Opinion Leaders): Find influencers in any niche (beauty, tech, food, fitness) by searching relevant keywords.
- Monitor competitors: Re-run keyword searches to see which accounts show up for your brand or category over time.
- Build social listening tools: Automate the discovery of creators talking about your brand or industry.
- Power marketing automation: Feed creator data into your CRM or outreach tools for partnership campaigns.
- Conduct market research: Understand who the visible voices are in a category on Douyin.
What is SandBase?
SandBase is a unified API gateway that aggregates many social media and data APIs under one consistent interface. Instead of dealing with different authentication methods and response formats for each platform, you call one endpoint with one API key.
For Douyin, the SandBase Douyin catalog lists 262 endpoints as of 2026-10-01, including user search, video search, and creator profiles, all callable through POST https://api.sandbase.ai/v1/api/<model> with one API key.

Caption: The SandBase Douyin catalog shows “262 SHOWN” endpoints, which is the source of the endpoint count above (captured 2026-10-02).
Scope: public, read-only data
This workflow returns public, read-only Douyin data. It needs a SandBase API key, and SandBase is not an official Douyin partner. It does not give you private-account data, DMs, owner-only analytics, or any publishing, messaging, or account actions.
SandBase user-search-v2 | Douyin Open Platform (open.douyin.com) | |
|---|---|---|
| Authentication | One SandBase API key | Developer app plus user/account authorization |
| Access scope | Public creator search results | Authorized, account-linked workflows |
| Typical use | Keyword creator discovery and research | Apps acting on behalf of authorized Douyin users |
Prerequisites
Before you start, you’ll need:
- A SandBase account: Sign up at sandbase.ai
- An API key: Generate one from your SandBase dashboard
- Credits: SandBase uses a credit system; as of 2026-10-01 the catalog lists
douyin/search/user-search-v2as Free.
For this endpoint you don’t register a Douyin developer app or implement a Douyin OAuth flow; the SandBase API key is the only credential in the request.
API Overview
Here’s the key information for keyword creator search on Douyin:
| Parameter | Value |
|---|---|
| Endpoint | https://api.sandbase.ai/v1/api/douyin/search/user-search-v2 |
| Method | POST |
| Model | douyin/search/user-search-v2 |
| Authentication | Bearer token (your SandBase API key) |
| Input | keyword (string), cursor (integer, 0 for the first page) |
| Output | A page of matching creator accounts |
Open the user-search-v2 API reference for the full request schema. This is the Model API POST /v1/api/... route from the endpoint reference, not the catalog’s GET /apis/v1/... listing. The request schema has only keyword and cursor; there is no result-count parameter, so you slice locally.

Caption: The user-search-v2 reference documents POST /v1/api/douyin/search/user-search-v2 with just two body fields, cursor (0 for the first page) and keyword (captured 2026-10-02).
If you already know a creator’s name or Douyin ID, douyin/creator/user-search (required user_name) is a lighter lookup. On 2026-10-01 I called it with {"user_name": "人民日报"} (the People’s Daily media account; run id db1e6236-5baf-43b4-824e-d14c557ce9de). It returned user_infos[] with only avatar, nick_name, short_id, and a numeric-string user_id (first entry: 人民日报, short_id rmrbxmt), with no follower counts. That’s why this tutorial uses user-search-v2 for keyword discovery.

Caption: The douyin/creator/user-search reference takes a single required user_name, the lighter name/ID lookup described above; this image predates the 2026-10-02 captures.
In my user-search-v2 runs on 2026-10-01, each result carried (among other fields):
nick_name: display namefans_cnt: follower countlike_cnt: total likes receivedpublish_cnt: number of postsavatar_url: avatar imageuser_id: a value insec_user_idformat (MS4wLjABAAAA...), usable in profile and post-list calls
These field names are observed-only, not documented guarantees. Bios and verification labels did not appear in these results.
Step 1: Your First API Call (curl)
Let’s search for Douyin creators related to 咖啡 (coffee):
curl -X POST https://api.sandbase.ai/v1/api/douyin/search/user-search-v2 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SANDBASE_API_KEY" \
-d '{"keyword": "咖啡", "cursor": 0}'
Understanding the Response
Tested on 2026-10-01 (UTC) with the generic keyword for coffee: the request above returned HTTP 200, status: completed, and one page of 30 accounts (run id c3e55399-822e-4fa4-83ac-42aba82f93b2). The endpoint reference documents the payload under outputs[0].data. Inside it, this endpoint wrapped results in one more data key next to code and message. Real response, trimmed to the first result and six of its fields:
{
"id": "c3e55399-822e-4fa4-83ac-42aba82f93b2",
"status": "completed",
"model": "douyin/search/user-search-v2",
"outputs": [
{
"data": {
"code": 0,
"message": "",
"data": {
"cursor": 30,
"has_more": true,
"user_list": [
{
"nick_name": "咖啡",
"fans_cnt": 2803302,
"like_cnt": 20239511,
"publish_cnt": 381,
"avatar_url": "https://p26.douyinpic.com/aweme/100x100/aweme-avatar/...",
"user_id": "MS4wLjABAAAA..."
}
]
}
}
}
]
}
The payload fields are observed in this run, not a documented schema. To get the next page, I sent the returned cursor as the next request’s cursor while has_more was true. In my test for 护肤 (skincare) on 2026-10-01, page 1 (cursor: 0) and page 2 (cursor: 30) each returned 30 accounts, and one account appeared on both pages (runs be6a6551-9d72-4c38-b629-5ac1cf2ed33c, 7edbfcce-79ca-45d6-a911-374351ffdd84). Deduplicate by user_id when you merge pages.
Step 2: Python Integration
For production use, here’s a clean Python implementation:
import requests
class DouyinUserSearch:
"""Search Douyin creators through the SandBase Model API."""
def __init__(self, api_key: str):
self.api_key = api_key
self.endpoint = "https://api.sandbase.ai/v1/api/douyin/search/user-search-v2"
def search_page(self, keyword: str, cursor: int = 0) -> dict:
"""Fetch one page of results. Returns the inner payload
({"cursor", "has_more", "user_list"} in my runs)."""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}",
}
payload = {"keyword": keyword, "cursor": cursor}
response = requests.post(self.endpoint, headers=headers, json=payload, timeout=60)
response.raise_for_status()
body = response.json()
outputs = body.get("outputs") or []
if body.get("status") != "completed" or not outputs:
raise RuntimeError(f"SandBase call did not complete: {body.get('status')} {body.get('error')}")
data = outputs[0].get("data") or {}
return data.get("data") or {}
def search(self, keyword: str, count: int = 10) -> list[dict]:
"""Return up to `count` unique creators, following `cursor` while `has_more` is true."""
users, seen, cursor = [], set(), 0
while len(users) < count:
page = self.search_page(keyword, cursor)
for user in page.get("user_list") or []:
if user.get("user_id") not in seen:
seen.add(user.get("user_id"))
users.append(user)
if not page.get("has_more") or page.get("cursor") is None:
break
cursor = page["cursor"]
return users[:count]
# Usage
api_key = "your_sandbase_api_key_here"
client = DouyinUserSearch(api_key)
# Search for coffee-related creators
users = client.search("咖啡", count=10)
for user in users:
print(f"Name: {user.get('nick_name')}")
print(f"Followers: {user.get('fans_cnt', 0):,}")
print(f"Posts: {user.get('publish_cnt')}")
print(f"sec_user_id: {user.get('user_id')}")
print("---")
Adding Error Handling
For production systems, add retry logic and proper error handling:
import time
from typing import Optional
def search_with_retry(
client: DouyinUserSearch,
keyword: str,
count: int = 10,
max_retries: int = 3
) -> Optional[list]:
"""Search with exponential backoff retry."""
for attempt in range(max_retries):
try:
return client.search(keyword, count)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429:
wait_time = 2 ** attempt
print(f"Rate limited. Retrying in {wait_time}s...")
time.sleep(wait_time)
else:
raise
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
return None
Step 3: Practical Use Cases
Use Case 1: KOL Discovery for Marketing Campaigns
Find top creators in the skincare niche and filter by follower count:
users = client.search("护肤", count=60)
# Filter for mid-tier influencers (100K-500K followers)
mid_tier_kols = [
user for user in users
if 100_000 <= user.get("fans_cnt", 0) <= 500_000
]
print(f"Found {len(mid_tier_kols)} mid-tier skincare KOLs")
for kol in mid_tier_kols:
print(f" {kol.get('nick_name')} — {kol.get('fans_cnt', 0):,} followers")
Use Case 2: Competitor Monitoring
Track accounts related to your brand or competitors:
competitors = ["品牌A", "品牌B", "品牌C"]
for brand in competitors:
users = client.search(brand, count=5)
print(f"\n{brand}: Found {len(users)} related accounts")
for user in users:
print(f" @{user.get('nick_name')} ({user.get('fans_cnt', 0):,} followers)")
Use Case 3: Building a Social Monitoring Agent
Combine creator keyword search with an AI agent framework to build automated social intelligence:
# Pseudocode for an AI agent workflow
keywords = ["你的品牌名", "行业关键词", "竞品名称"]
for keyword in keywords:
creators = client.search(keyword, count=10)
# Store results in your database
for creator in creators:
save_to_db(creator) # key on creator["user_id"]
# Alert if new high-follower accounts appear
new_accounts = filter_new_accounts(creators)
if new_accounts:
send_alert(f"New accounts found for '{keyword}': {new_accounts}")
Combining with Other SandBase APIs
You can combine several search endpoints for cross-platform research. Key fields only; open each reference for the full request schema:
| Platform | API Model | Key fields | Use Case |
|---|---|---|---|
| Douyin User Search | douyin/search/user-search-v2 | keyword, cursor | Find creators |
| Douyin Video Search | douyin/search/video-search-v2 | keyword, cursor (plus optional filters) | Find content by keyword |
| Xiaohongshu Note Search | xiaohongshu/app-v2/search-notes | keyword, page (plus optional fields) | Cross-platform research |
| Weibo User Search | weibo/web-v2/user-search | query, page (plus optional filters) | Find matching Weibo accounts |
Each of these returned non-empty results for the coffee keyword in my runs on 2026-10-01 (runs a102bf5b-61bf-42ac-803a-da55633a38e6, 846c4b40-b260-401c-ac2f-254175315626, 4e4e6cf4-9170-49f2-aa42-efd1e0be090d). Their payload shapes differ, so check each reference before parsing.
The user_id from search results is a sec_user_id, which douyin/web/user-profile and douyin/web/user-post-videos accept. Those downstream endpoints have their own conditions (the post-list reference notes the Web API can be unstable and accepts an optional user cookie), so check each reference rather than assuming they behave like user-search-v2.
For more details on Douyin data APIs, check out our guide on Douyin Data API on SandBase. If you’re building AI agents that consume social data, read Social Media Data APIs for AI Agents in 2026.
Pricing and Rate Limits
SandBase meters usage per call against your credit balance, and you can check credit usage in the dashboard. As of 2026-10-01, the catalog lists douyin/search/user-search-v2 as Free, and the model page shows the same:

Caption: The douyin/search/user-search-v2 model page lists Base price Free, sync execution and 2 input fields (captured 2026-10-02).
See the SandBase pricing page for current plans. If you get HTTP 429, back off and retry as shown above.
Tips for Best Results
- Try Chinese keywords first: Douyin’s audience is mostly Chinese-speaking, so Chinese keywords are a sensible starting point; compare against English terms for your niche.
- Be specific: A narrower keyword like
精品咖啡(specialty coffee) tends to give a more targeted list than咖啡(coffee). - Combine searches: Run multiple searches with related keywords to build a comprehensive list.
- Cache results: If you don’t need fresh numbers on every run, cache results and refresh them on a schedule that fits your use case.
- Respect rate limits: Implement backoff logic to handle 429 responses gracefully.
Summary
SandBase’s user-search-v2 endpoint gives you a simple way to search public Douyin creator accounts by keyword. With one API call per page, you can:
- Find relevant KOLs for marketing campaigns
- Monitor which accounts appear for competitor keywords
- Build automated social listening tools
- Feed public creator data into AI agents
Get started by signing up for SandBase, then open the user-search-v2 API reference and make your first call.