For AI

How-to guides

Douyin API in Python: videos, profiles and comments (2026)

Douyin's official Open Platform serves the data of users who authorise your app, so this guide calls five okdata endpoints from plain requests instead: video search, video detail, account profile, account videos and video comments. The worked example is 6 calls and costs $0.03; a failed call is not charged.

Updated

Is there an official Douyin API for this? The Douyin Open Platform is built around user authorisation. Its profile call, 获取用户公开信息, takes an access_token and an open_id that your app only receives after that user logs in and grants the user_info scope. The platform also lists a keyword video search (scope aweme.dy.video_search), but it sits behind a separate permission your app has to be granted. If you build for accounts that log in to your app, or your app holds that permission, the official route is the right one. More on the split in what the Douyin Open Platform covers.

This guide is for the other case: you want public Douyin data in a Python script without an app review, OAuth flow, cookie or signature code. You end with a small client you can reuse: one helper that handles errors and retries, a pager with a page cap, five endpoints and a JSON report.

Step by step

Step 1: set up

You need Python 3.9 or newer, requests and an API key in an environment variable. There is no SDK to install.

pip install requests
export OKDATA_API_KEY=okd_...

Every call is a GET to https://api.okdata.online plus the endpoint path, with the key as a bearer token. A success has "code": "ok", the data under data, and for lists a page object. An error has a code, a message, a request_id and a retry hint: yes means try again later (wait retry_after_seconds when it is set), anything else means fix the request or skip it.

Step 2: search videos

Douyin video search takes query and sort: relevance (the default), latest or most_liked. One call returns about 20 videos for $0.02. Each has id, the caption in text, author (with author.id, the sec_uid), metrics with likes, comments, shares and favorites, published_at and hashtags. Image posts come with type: "image" and their images.

curl -G "https://api.okdata.online/v1/douyin/videos/search" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'query=露营装备' \
  --data-urlencode 'sort=most_liked'

Douyin video detail takes id or url, and a v.douyin.com share link works as url. It costs $0.002. Use it to refresh the counts of a video you already know, or when all you have is a link someone pasted. With view=full you also get ext.duration_ms and the music title in ext.music.

curl -G "https://api.okdata.online/v1/douyin/videos/get" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'id=7438215906473820455' \
  --data-urlencode 'view=full'

Step 4: the author's profile

Douyin account profile takes the sec_uid as id, or a profile or share link as url, for $0.002. You get followers, following, posts (videos published), likes (total likes received), bio and verified. username is the Douyin number people see in the app.

curl -G "https://api.okdata.online/v1/douyin/users/get" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'id=MS4wLjABAAAAk3Vb9QpZr2LxWc7nYfTe1HdJ6sGuA0mKiOyPzR4tE8w'

Step 5: the author's videos

Douyin account videos needs the sec_uid as id and returns about 20 videos per call, newest first, for $0.002. Page with cursor like every list.

Step 6: comments under a video

Douyin video comments needs the video id and returns about 20 top-level comments per call for $0.002, in Douyin's hot order (sort=hot is the only value). Each comment has text, author, likes, replies, published_at and ip_location.

curl -G "https://api.okdata.online/v1/douyin/videos/comments/list" \
  -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'id=7438215906473820455'

Step 7: the whole script

The script runs the worked example: search, take the most-liked video, fetch its detail, its author's profile and latest videos, two pages of comments, and write douyin_report.json. call sends one Idempotency-Key per logical call and reuses it on retries, so a retried request is never charged twice.

import json
import os
import time
import uuid
import requests

API = "https://api.okdata.online"
SESSION = requests.Session()
SESSION.headers["Authorization"] = f"Bearer {os.environ['OKDATA_API_KEY']}"
COMMENT_PAGES = 2  # each page is one call


class ApiError(Exception):
    def __init__(self, body):
        super().__init__(f"{body['code']}: {body['message']} (request {body['request_id']})")
        self.code = body["code"]


def call(path, **params):
    key = str(uuid.uuid4())  # same key on every retry: a replay is not charged again
    for attempt in range(3):
        body = SESSION.get(API + path, params=params, headers={"Idempotency-Key": key}, timeout=60).json()
        if body["code"] == "ok":
            return body
        if body.get("retry") == "yes" and attempt < 2:
            time.sleep(body.get("retry_after_seconds") or 5)
            continue
        raise ApiError(body)


def pages(path, max_pages, **params):
    """Yield items page by page; stop at max_pages or when has_more is false."""
    cursor = None
    for _ in range(max_pages):
        body = call(path, **params, **({"cursor": cursor} if cursor else {}))
        yield from body["data"]["items"]
        if not body["page"]["has_more"]:
            return
        cursor = body["page"]["next_cursor"]


found = call("/v1/douyin/videos/search", query="露营装备", sort="most_liked")["data"]["items"]
if not found:
    raise SystemExit("no videos for that query")
top = max(found, key=lambda v: v["metrics"]["likes"] or 0)

video = call("/v1/douyin/videos/get", id=top["id"], view="full")["data"]["item"]
author = call("/v1/douyin/users/get", id=video["author"]["id"])["data"]["item"]
latest = call("/v1/douyin/users/videos/list", id=author["id"])["data"]["items"]
comments = list(pages("/v1/douyin/videos/comments/list", COMMENT_PAGES, id=video["id"]))

report = {
    "video": {"id": video["id"], "text": video["text"], "likes": video["metrics"]["likes"],
              "comments": video["metrics"]["comments"], "music": video.get("ext", {}).get("music")},
    "author": {"sec_uid": author["id"], "name": author["name"], "followers": author["followers"],
               "videos": author["posts"], "likes": author["likes"]},
    "latest_videos": [{"id": v["id"], "text": v["text"], "published_at": v["published_at"],
                       "likes": v["metrics"]["likes"]} for v in latest],
    "comments": [{"text": c["text"], "likes": c["likes"], "replies": c["replies"],
                  "ip_location": c["ip_location"]} for c in comments],
}
with open("douyin_report.json", "w", encoding="utf-8") as f:
    json.dump(report, f, ensure_ascii=False, indent=2)

To go deeper, raise COMMENT_PAGES or wrap the account videos call in pages too. Ten pages of comments under each of 20 videos is 200 calls, $0.40.

Good to know

  • No play counts. Douyin does not show view counts publicly, so metrics.views is null on every video and meta.unavailable says platform. title is null too: a Douyin caption is in text.
  • Three kinds of account ID. The sec_uid (starts with MS4wLjABAAAA) is what the account endpoints take. The Douyin number is username. The numeric uid appears as ext.uid with view=full. See how to get a sec_uid.
  • Links work as input. Video detail and account profile take share links directly; converting a share link to a video ID explains the formats.
  • Deleted is free. A removed video or a banned account returns not_found, which is not charged. The script raises ApiError with code == "not_found"; catch it and move on in a batch job.
  • Replies are counted, not listed. Comments carry replies, the number of replies under them, but not the reply text.
  • Spend is bounded by your caps. Each page is a call, so max_pages in pages is also a spending cap. Errors cost nothing.

For comments across many videos at once, the step-by-step Douyin comments export goes from one search to a CSV. To read the comments for opinions, see turning Douyin comments into a sentiment summary.

What the example costs

One search for 露营装备 (camping gear), the most-liked video's detail, its author's profile and latest videos, and two pages of comments under that video

EndpointCallsPriceSubtotal
Douyin video search1$0.02$0.02
Douyin video detail1$0.002$0.002
Douyin account profile1$0.002$0.002
Douyin account videos1$0.002$0.002
Douyin video comments2$0.002$0.004
Total6$0.03

Prices in force when this page was built. A failed call costs nothing.

In your AI (MCP)

Connect the MCP server once, then say what you want. The agent finds these endpoints, reads their prices and calls them on your balance.

SaySearch Douyin for 露营装备 (camping gear), open the most-liked video, look up its author, list the author's latest videos and read the first two pages of comments under that video. Summarise what the comments ask about.

What the agent sends to the call tool first
{
  "endpoint": "douyin.videos.search",
  "params": {
    "query": "露营装备"
  },
  "idempotency_key": "<a new UUID>"
}

Set up the MCP server →

Sources

  1. 抖音开放平台 OpenAPI: 获取用户公开信息developer.open-douyin.com · read
  2. 抖音开放平台 OpenAPI: 抖音视频搜索developer.open-douyin.com · read

Connect once, then just ask.

Every new key comes with $0.10 to try it. One sentence connects your agent.

Start free
Connect your AI

Paste this into your agent

Read https://okdata.online/agents.md and set up okdata for me; my key is in the OKDATA_API_KEY environment variable.

Claude Code, Cursor, Codex and other agents that can open a link set themselves up from it.

MCP serverhttps://api.okdata.online/mcp