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

> A Python client for public Douyin data: keyword search, video detail, account profile, an account's videos and comments, with paging, retries and the cost of a run.

Canonical page: https://okdata.online/guides/douyin-api-python/

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 2026-11-12

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](https://okdata.online/answers/douyin-open-platform-api/).

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.

```bash
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](https://okdata.online/apis/douyin/videos/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`.

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

### Step 3: one video by ID or link

[Douyin video detail](https://okdata.online/apis/douyin/videos/get/) 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`.

```bash
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](https://okdata.online/apis/douyin/users/get/) 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.

```bash
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](https://okdata.online/apis/douyin/users/videos/list/) 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](https://okdata.online/apis/douyin/videos/comments/list/) 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`.

```bash
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.

```python
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](https://okdata.online/answers/douyin-sec-uid/).
- **Links work as input.** Video detail and account profile take share links directly; [converting a share link to a video ID](https://okdata.online/answers/douyin-share-link-to-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](https://okdata.online/guides/douyin-video-comments/) goes from one search to a CSV. To read the comments for opinions, see [turning Douyin comments into a sentiment summary](https://okdata.online/answers/douyin-export-comments-sentiment/).

## 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

| Endpoint | Calls | Price | Subtotal |
|---|---|---|---|
| [Douyin video search](https://okdata.online/apis/douyin/videos/search/) | 1 | $0.02 | $0.02 |
| [Douyin video detail](https://okdata.online/apis/douyin/videos/get/) | 1 | $0.002 | $0.002 |
| [Douyin account profile](https://okdata.online/apis/douyin/users/get/) | 1 | $0.002 | $0.002 |
| [Douyin account videos](https://okdata.online/apis/douyin/users/videos/list/) | 1 | $0.002 | $0.002 |
| [Douyin video comments](https://okdata.online/apis/douyin/videos/comments/list/) | 2 | $0.002 | $0.004 |
| Total | 6 |  | $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.

Say: Search 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.

```json
{
  "endpoint": "douyin.videos.search",
  "params": {
    "query": "露营装备"
  },
  "idempotency_key": "<a new UUID>"
}
```

MCP: `https://api.okdata.online/mcp`

## Endpoints in this guide

- [Douyin video search](https://okdata.online/apis/douyin/videos/search/) `douyin.videos.search`: $0.02 per call · about 20 videos per page
- [Douyin video detail](https://okdata.online/apis/douyin/videos/get/) `douyin.videos.get`: $0.002 per call
- [Douyin account profile](https://okdata.online/apis/douyin/users/get/) `douyin.users.get`: $0.002 per call
- [Douyin account videos](https://okdata.online/apis/douyin/users/videos/list/) `douyin.users.videos.list`: $0.002 per call · about 20 videos per page
- [Douyin video comments](https://okdata.online/apis/douyin/videos/comments/list/) `douyin.videos.comments.list`: $0.002 per call · about 20 comments per page

## More about Douyin

- [Douyin API](https://okdata.online/apis/douyin/)
- [How to export Douyin video comments in bulk](https://okdata.online/guides/douyin-video-comments/)
- [How to find Douyin Xingtu creators and get their rate cards](https://okdata.online/guides/douyin-xingtu-creator-rates/)
- [What is Douyin's a_bogus parameter, and do I need to generate it to get Douyin data?](https://okdata.online/answers/douyin-a-bogus-signature/)
- [Can Douyin's official open platform API get other people's videos and comments?](https://okdata.online/answers/douyin-open-platform-api/)
- [My Douyin scraper stopped working after a signature change. Should I fix it or switch to an API?](https://okdata.online/answers/douyin-scraper-broke-signature/)
- [How do I track a competitor's Douyin account every day?](https://okdata.online/answers/douyin-competitor-account-tracking/)
- [My Douyin tool keeps saying the cookie is invalid. How do I stop depending on cookies?](https://okdata.online/answers/douyin-cookie-expired/)
- [How do I get all the videos from a Douyin account?](https://okdata.online/answers/douyin-creator-all-videos/)
- [How to collect Douyin comments: API, crawler or no-code (2026)](https://okdata.online/compare/douyin-comment-scraping/)
- [Douyin data APIs: official vs third-party vs open-source (2026)](https://okdata.online/compare/douyin-data-apis/)
- [Official platform APIs vs third-party data APIs (2026)](https://okdata.online/compare/official-apis-vs-data-apis/)
- [Scraping it yourself vs a per-call data API: cost, upkeep and risk](https://okdata.online/compare/scraping-vs-data-api/)
- [How to choose a social media data API (2026)](https://okdata.online/compare/social-media-data-apis/)

## Sources

- [抖音开放平台 OpenAPI: 获取用户公开信息](https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/account-management/get-account-open-info) (read 2026-11-12)
- [抖音开放平台 OpenAPI: 抖音视频搜索](https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/douyin-search-capability/aweme-dy-video-search) (read 2026-11-12)
