How to Collect Douyin Video Data: Search, Details and Comments
Use Just One API to search Douyin videos, retrieve video details and collect comments. Includes setup, searchId pagination and a Python example that saves JSON responses.
Where to start with Douyin video data
To research a topic on Douyin, start with a keyword search, then use the returned video IDs to retrieve details and comments. Just One API provides a separate endpoint for each step, accessible with the same API token.
This tutorial searches for “露营装备” (camping gear), selects a few videos, retrieves their details and first page of comments, and saves the responses as JSON. If you already know the video ID, you can skip the search and go straight to details or comments.
The example collects structured data about videos. It does not download video files or retrieve Douyin E-commerce products or Xingtu creator marketing data, which have separate endpoints.
Get an API token and test in the documentation
Create a Just One API account, obtain your API token, and use the interactive documentation to try the APIs for free. One token gives you access to APIs across platforms, with pay-as-you-go billing after the trial. Check your account for the trial allowance available for each endpoint.
Open Douyin Video Search V4, enter your token and the keyword “露营装备”, and request page 1. Check that the response body's business code is 0 before processing data. A successful HTTP status alone does not confirm a successful API operation.
This tutorial uses three GET endpoints:
- Video search:
/api/douyin/search-video/v4, with the requiredkeywordparameter. - Video details:
/api/douyin/get-video-detail/v2, with the requiredvideoIdparameter. - Video comments:
/api/douyin/get-video-comment/v1, with the requiredawemeIdparameter, for top-level comments.
All three also require the token query parameter. The Python example reads it from an environment variable. Keep real tokens out of public code and avoid logging complete request URLs that contain them.
Step 1: Search for videos by keyword
The example uses keyword=露营装备, sortType=_0, publishTime=_0, duration=_0, and page=1: general ranking with no publication-time or duration filter. Change these parameters to suit your research question.
sortType:_0for general ranking,_1for more likes, or_2for newest.publishTime:_0for no limit,_1for the last 24 hours,_7for the last 7 days, or_180for the last 6 months.duration:_0for no limit,_1for under 1 minute,_2for 1–5 minutes, or_3for over 5 minutes.
In the current public response example, ordinary video cards are in data.business_data. A card's video ID is at data.aweme_info.aweme_id within that card. Search responses can contain other card types, so the script only processes cards containing this video ID.
Pass both page and searchId when fetching the next page
The first page does not need searchId. For page 2 and later, increment page and pass the previous response's data.business_config.next_page.search_id as the next request's searchId.
Stop when data.business_config.has_more is 0. Keep the keyword and filters unchanged while paging through one search. If you change them, start again at page 1 without reusing the previous search ID.
See the Video Search V4 documentation for the full parameter list. Search results reflect the platform's available search coverage; they should not be treated as every video about a topic.
Step 2: Retrieve video details
Take an aweme_id from the search results and send it as videoId to the details endpoint. The same ID can have different request parameter names across endpoints.
The current public Video Details V2 example places the video object at data.aweme_detail, with fields such as desc, create_time, author, and statistics. The script saves the complete response so you can inspect the fields before mapping them into your own data model.
Engagement metrics are snapshots from the request. Some fields may be missing, empty, or unsuitable as a complete measure of activity. A field name alone does not establish that its value is a reliable total for views or impressions.
Step 3: Retrieve video comments
Send the same video ID as awemeId to Video Comments V1, starting with page=1.
In the current public response example, the list is at data.comments. Comment fields include cid, text, create_time, and digg_count. To fetch additional pages, increment page, use the returned data.has_more to decide whether to continue, and set a maximum page count.
This endpoint accepts a page number. Do not send the video search searchId or treat the response's cursor as a request parameter for this endpoint. The script below retrieves only the first comment page for each selected video.
Top-level comments and their replies are separate retrieval steps. Use the Comment Replies endpoint if you need nested discussion. A top-level comment list is not a complete comment tree.
Python example: Save search results, details and comments
Install the dependency and set your token. Replace your_token with your own value. These commands work in a macOS or Linux terminal.
python3 -m pip install requests
export JUSTONEAPI_TOKEN='your_token'Save the following as douyin_sample.py and run python3 douyin_sample.py. It requests at most 2 search pages, then details and the first comment page for at most 3 unique videos: up to 8 API requests in total. It makes fewer requests if pagination ends early or an error stops the run.
These limits keep the example small; they are not platform quotas. The code follows the current documentation and public response examples. Actual records depend on the responses received when you run it.
import json
import os
from datetime import datetime, timezone
from pathlib import Path
import requests
BASE_URL = "https://api.justoneapi.com"
TOKEN = os.environ.get("JUSTONEAPI_TOKEN", "")
KEYWORD = "露营装备"
MAX_SEARCH_PAGES = 2
MAX_VIDEOS = 3
def call_api(path, **params):
try:
response = requests.get(
BASE_URL + path,
params={"token": TOKEN, **params},
timeout=120,
)
except requests.RequestException:
raise RuntimeError("Network error or timeout") from None
if response.status_code != 200:
raise RuntimeError(f"HTTP {response.status_code}")
try:
result = response.json()
except ValueError:
raise RuntimeError("Response is not valid JSON") from None
if not isinstance(result, dict) or result.get("code") != 0:
code = result.get("code") if isinstance(result, dict) else None
raise RuntimeError(f"API failed: code={code}; check the docs")
if not isinstance(result.get("data"), dict):
raise RuntimeError("Unexpected data shape; check the response")
return result
def save_json(folder, name, result):
(folder / name).write_text(
json.dumps(result, ensure_ascii=False, indent=2),
encoding="utf-8",
)
def main():
if not TOKEN or TOKEN == "your_token":
raise RuntimeError("Set JUSTONEAPI_TOKEN before running")
run_id = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ")
folder = Path("douyin-output") / run_id
folder.mkdir(parents=True, exist_ok=False)
video_ids = []
seen = set()
search_id = None
for page in range(1, MAX_SEARCH_PAGES + 1):
params = dict(
keyword=KEYWORD, sortType="_0", publishTime="_0",
duration="_0", page=page,
)
if page > 1:
params["searchId"] = search_id
result = call_api("/api/douyin/search-video/v4", **params)
save_json(folder, f"search-{page}.json", result)
data = result["data"]
for card in data.get("business_data") or []:
info = (card.get("data") or {}).get("aweme_info") or {}
video_id = info.get("aweme_id")
if video_id and str(video_id) not in seen:
video_id = str(video_id)
seen.add(video_id)
video_ids.append(video_id)
config = data.get("business_config") or {}
if config.get("has_more") not in (1, "1"):
break
search_id = (config.get("next_page") or {}).get("search_id")
if page < MAX_SEARCH_PAGES and not search_id:
raise RuntimeError("Missing next search_id; inspect saved JSON")
selected = video_ids[:MAX_VIDEOS]
save_json(folder, "selected-video-ids.json", selected)
for index, video_id in enumerate(selected, start=1):
detail = call_api(
"/api/douyin/get-video-detail/v2", videoId=video_id,
)
save_json(folder, f"video-{index}-detail.json", detail)
comments = call_api(
"/api/douyin/get-video-comment/v1", awemeId=video_id, page=1,
)
save_json(folder, f"video-{index}-comments-1.json", comments)
print(f"Saved {len(selected)} video samples to {folder}")
if __name__ == "__main__":
try:
main()
except RuntimeError as error:
raise SystemExit(str(error)) from NoneEach run creates a new directory under douyin-output, containing search responses, selected video IDs, video details, and first-page comment responses. You can then extract fields into CSV or a database while retaining the original JSON for reference.
The script deduplicates video IDs before requesting details. For larger comment collections, use the video ID together with comment cid as a deduplication key and follow the actual response's pagination signals. Keep unavailable fields null rather than silently turning missing data into a numeric zero.
Handle failures before scaling up
For easier debugging, the example stops on a failed call and leaves successful responses in the output directory. It does not retry automatically. Running it again creates a new directory and makes new requests.
code=0: the operation succeeded and the data can be processed.code=301: collection failed; consider a bounded retry policy.code=302: a limit was reached; reduce the request rate and followRetry-Afterwhen provided.code=100,400,600,601, or602: check the token, parameters, permissions, balance, or token spending cap before retrying.code=303: the daily quota has been exceeded; wait for the quota window to reset.
See the API Usage Guide for the full rules. Before collecting a larger dataset, read the retry and concurrency guide and add checkpoints, failure records, and bounded retries.
Common questions
Do I need search if I already have a video ID?
No. Pass the ID directly as videoId for details or awemeId for comments. This avoids unnecessary search requests. If you only have a share link, start with the Share Link Resolution endpoint.
Will this retrieve every video and comment?
No. Search coverage, content visibility, and available comments depend on the platform. This example also imposes explicit page and video limits, so it is a sample collection rather than an exhaustive dataset. Record the keyword, filters, collection time, and coverage limits alongside any analysis.
How do I retrieve videos from one creator?
Use User Published Videos V1 with secUid and follow that endpoint's cursor pagination. You can then retrieve details and comments for the returned videos as needed.
Can I use these endpoints for TikTok?
These endpoints target Douyin. TikTok has a separate TikTok API group. Choose the group for the platform you need rather than swapping platform names or mixing IDs.
Collect your first Douyin data sample
Create a Just One API account, get your API token, and test a keyword for free in the Douyin Video Search documentation. Once the search, detail, and comment responses meet your needs, adjust the collection scope and connect the workflow to your application. Use one token across platforms and pay for actual API usage.
Continue with Just One API
Log in to the Dashboard for your token, read the full API docs, or open the MCP GitHub project for the latest configuration.