For AI

How-to guides

TikTok comments in Python for sentiment analysis (2026)

Two endpoints: TikTok video search to pick the videos, then TikTok video comments, page by page, for each one. The worked example below is 11 calls and costs $0.022; a failed call is not charged.

Updated

The job: you want to know how people feel about a product or topic on TikTok, measured on what they write, not on view counts. That means a few hundred real comments from the videos where the discussion happens, in a file a sentiment model or an LLM can read. TikTok's own Research API has comments, but only for researchers TikTok approves through an application; what a company can use instead covers that route. Here each call is an HTTPS GET with an API key, no TikTok account or login, and requests is the only library.

You end with tiktok_comments.csv: one row per comment with the video it came from, the video's language, the comment text, likes, reply count and time, deduplicated and with empty rows dropped.

Step by step

Set the key once: export OKDATA_API_KEY=okd_.... Every answer has code ("ok" on success); lists come in data.items with a page that carries the next cursor.

Step 1: find the videos where people talk

TikTok video search takes query and sort: relevance (the default), most_liked or latest. TikTok's search leans on relevance, so latest is not a strict date order; filter on published_at yourself if dates matter. One call returns about 30 videos for $0.002, each with id, the caption in text, lang, published_at, author.username, and metrics.views, metrics.likes, metrics.comments and metrics.shares. Pick by metrics.comments: a video with 4 million views and 80 comments is no use for this.

curl -G "https://api.okdata.online/v1/tiktok/videos/search" -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'query=air fryer' --data-urlencode 'sort=most_liked' \
  --data-urlencode 'fields=id,text,lang,author.username,metrics.comments,published_at'

Step 2: page through the comments

TikTok video comments takes the video's numeric ID as id (such as 7429815063927400734). One call returns about 50 top-level comments for $0.002, each with id, text, likes, replies (the reply count), published_at, author.username and, where TikTok shows one, ip_location. For the next page, send page.next_cursor back as cursor, unchanged; stop when page.has_more is false.

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

Step 3: the full script

The script searches once, keeps the VIDEOS videos with the most comments, reads up to PAGES_PER_VIDEO pages under each, cleans the text and writes the CSV. The same number of pages per video keeps one viral video from drowning out the rest. The helper retries rate limits and busy upstreams with the same Idempotency-Key, so a retry is never charged twice, and skips videos deleted since the search.

import csv
import os
import re
import time
import uuid

import requests

API = "https://api.okdata.online"
KEY = os.environ["OKDATA_API_KEY"]
QUERY = "air fryer"
VIDEOS = 5            # videos to read
PAGES_PER_VIDEO = 2   # comment pages per video; each page is one call


def call(path, **params):
    headers = {"Authorization": f"Bearer {KEY}", "Idempotency-Key": str(uuid.uuid4())}
    for attempt in range(4):
        body = requests.get(API + path, headers=headers, params=params, timeout=60).json()
        if body["code"] == "ok":
            return body
        if body["code"] == "not_found":
            return None  # deleted or private: not charged
        if body.get("retry") in ("yes", "same_key"):
            time.sleep(body.get("retry_after_seconds") or 2 ** attempt)
            continue
        raise RuntimeError(f"{body['code']}: {body['message']} (request {body['request_id']})")
    raise RuntimeError(f"{path}: still failing after 4 tries")


def comments(video_id, max_pages):
    cursor = None
    for _ in range(max_pages):
        body = call("/v1/tiktok/videos/comments/list", id=video_id, **({"cursor": cursor} if cursor else {}))
        if body is None:
            return
        yield from body["data"]["items"]
        if not body["page"]["has_more"]:
            return
        cursor = body["page"]["next_cursor"]


def clean(text):
    return re.sub(r"\s+", " ", text or "").strip()


videos = call("/v1/tiktok/videos/search", query=QUERY, sort="most_liked")["data"]["items"]
videos = sorted(videos, key=lambda v: v["metrics"]["comments"] or 0, reverse=True)[:VIDEOS]

seen = set()
with open("tiktok_comments.csv", "w", newline="", encoding="utf-8-sig") as f:
    out = csv.writer(f)
    out.writerow(["video_id", "video_lang", "video_caption", "comment_id", "text", "likes", "replies", "published_at", "author"])
    for v in videos:
        for c in comments(v["id"], PAGES_PER_VIDEO):
            text = clean(c["text"])
            if not text or c["id"] in seen:
                continue
            seen.add(c["id"])
            out.writerow([v["id"], v["lang"], clean(v["text"])[:120], c["id"], text,
                          c["likes"], c["replies"], c["published_at"], c["author"]["username"]])

print(f"{len(seen)} comments from {len(videos)} videos")

That is the worked example: 1 search and 10 comment pages, about 500 comments. For a bigger sample, 20 videos at 4 pages each is 80 comment calls, $0.16 plus the search.

Step 4: score it

The CSV is ready for whatever does the scoring. Three habits make the result more honest:

  • Weight by likes. A complaint with 900 likes speaks for more people than one with none. Keep likes next to the score and report both the share of comments and the share of likes.
  • Handle language. Comments carry no language field. video_lang is a fair hint for the thread; mixed threads need a multilingual model or a language detector.
  • Read a sample. Sarcasm and slang fool every model. Read 30 rows of each label before you trust the split.

An LLM works well on batches of 50 to 100 comments with the video caption as context: ask for a label per comment plus the three most common praises and complaints. TikTok comments for sentiment analysis shows that end of the pipeline.

Good to know

  • Top-level comments only. Each comment carries its reply count, not the reply text, so your row count will be lower than the video's metrics.comments, which includes replies.
  • Order. Comments come in TikTok's own order; there is no sort parameter. Two pages per video is a sample of what TikTok puts first, not a random sample.
  • Locations. ip_location is filled only where TikTok shows one; treat it as optional.
  • Trimming. fields=id,text,likes,replies,published_at keeps the answer short when a model reads it directly. It does not change the price.
  • Free cases. A video deleted between search and comments answers not_found, which is free, like rate limits and every other error. The same request with the same Idempotency-Key within 24 hours comes back with meta.replayed: true and no new charge.

For a single video exported to Excel, exporting TikTok comments to CSV is the shorter path.

What the example costs

One search for air fryer, then 2 pages of comments (about 100) under each of the 5 videos with the most comments

EndpointCallsPriceSubtotal
TikTok video search1$0.002$0.002
TikTok video comments10$0.002$0.02
Total11$0.022

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 TikTok for air fryer, take the 5 videos with the most comments, get about 100 comments under each and tell me what people like and complain about, with a rough positive/negative split.

What the agent sends to the call tool first
{
  "endpoint": "tiktok.videos.search",
  "params": {
    "query": "ai agents"
  },
  "idempotency_key": "<a new UUID>"
}

Set up the MCP server →

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