Answers

How much does it cost to download a creator's full post history?

Short answer

Backfilling an account on okdata costs one call per page of its posts. A Douyin creator with 600 videos is 30 pages, $0.06; 600 Xiaohongshu notes cost $0.60; 600 X posts cost $0.18. A WeChat Official Account with 600 articles takes 60 pages of ten, $2.40.

A competitor review often starts with one question: what has this account published since it started, and which posts took off? Answering it means walking the account's post list from newest to oldest, one page per call. The cost is pages times the price per page, and pages are the post count divided by the page size.

Cost by account size

Platform Endpoint Posts per page 600 posts 3,000 posts
Douyin Douyin account videos 20 $0.06 $0.30
Xiaohongshu Xiaohongshu account notes 20 $0.60 $3.00
X X account posts 20 $0.18 $0.90
WeChat Official Account Official Account article history 10 $2.40 $12.00

Each list item already carries the text, publish time and metrics, so a backfill rarely needs per-post detail calls. Finding a WeChat account's original ID first is one account search, $0.058 per account returned.

A backfill that survives a crash

Write each page to disk as soon as it arrives, and derive each page's Idempotency-Key from the account and the cursor. If the script dies and you rerun it within 24 hours, every page it already paid for comes back from storage for free.

import hashlib, json, os, requests

URL = "https://api.okdata.online/v1/douyin/users/videos/list"
KEY = os.environ["OKDATA_API_KEY"]

def backfill(sec_uid, path):
    cursor = None
    with open(path, "w", encoding="utf-8") as out:
        while True:
            page_key = hashlib.sha256(f"{sec_uid}|{cursor}".encode()).hexdigest()
            h = {"Authorization": f"Bearer {KEY}", "Idempotency-Key": page_key}
            params = {"id": sec_uid, **({"cursor": cursor} if cursor else {})}
            body = requests.get(URL, headers=h, params=params, timeout=60).json()
            if body["code"] != "ok":
                raise RuntimeError(f"{body['code']}: {body['message']}")
            for post in body["data"]["items"]:
                out.write(json.dumps(post, ensure_ascii=False) + "\n")
            if not body["page"]["has_more"]:
                return
            cursor = body["page"]["next_cursor"]

A rerun starts from the first page again, but the pages it replays show meta.replayed: true and a charge of zero.

Limits to plan for

  • You get what the platform shows publicly. Hidden or deleted posts are not in the list, and page.has_more: false means you have reached the end of what is visible.
  • The result is post data and media links. Video files are not downloaded for you; tools such as yt-dlp do that well.
  • If the account is your own, the platform's creator dashboard has reach and audience numbers that no public endpoint returns.

Ongoing tracking after the backfill is cheaper still: see competitor monitoring.

Updated