Scrape TikTok comments and replies with Python
Collect the comments on any public TikTok video, and the replies under them, as JSON: text, likes, reply count, language, time and whether the creator liked it. Then save them to a CSV. One request returns a page of comments, usually 33–42.
TikTok's official APIs don't give companies other creators' comments: the Research API is for academic and not-for-profit research only. Collecting them yourself means building a scraper and keeping it working as TikTok changes. The TikTok Video & Creator API returns them as clean JSON instead.
Setup
You need Python 3, requests (pip install requests) and a key from the RapidAPI listing. Put the key in an environment variable called RAPIDAPI_KEY. The script below makes at most 15 requests, so the free plan's 100 requests are enough to try it.
import csv
import os
import time
from collections import Counter
from urllib.parse import quote
import requests
BASE = "https://tiktok-video-creator-api.p.rapidapi.com"
HEADERS = {
"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"],
"X-RapidAPI-Host": "tiktok-video-creator-api.p.rapidapi.com",
}
def get(path, **params):
"""GET a path and return the JSON. Retries rate limits and upstream errors."""
for attempt in range(4):
response = requests.get(BASE + path, headers=HEADERS, params=params, timeout=30)
if response.status_code in (429, 502, 503) and attempt < 3:
time.sleep(2 ** attempt)
continue
response.raise_for_status()
return response.json()
Pick the video
Use the video ID, the long number in a link like https://www.tiktok.com/@zachking/video/7655004069190192398. The endpoints also accept the whole tiktok.com link, URL-encoded, in place of the ID. Short links (vm.tiktok.com/…) aren't resolved; open them in a browser first to get the full link.
video = "7655004069190192398"
# or: video = quote("https://www.tiktok.com/@zachking/video/7655004069190192398", safe="")
Read one page
curl --request GET \
--url 'https://tiktok-video-creator-api.p.rapidapi.com/v1/tiktok/videos/7655004069190192398/comments' \
--header "X-RapidAPI-Key: $RAPIDAPI_KEY" \
--header 'X-RapidAPI-Host: tiktok-video-creator-api.p.rapidapi.com'
Response shape, shortened to one comment. Counts are from a live response; the commenter's details and the text are placeholders
{
"video_id": "7655004069190192398",
"total": 105316,
"count": 1,
"has_more": true,
"next_cursor": "50",
"comments": [
{
"id": "7655354445920699138",
"video_id": "7655004069190192398",
"text": "This is amazing",
"created_at": "2026-06-25T15:25:17Z",
"likes": 1824941,
"reply_count": 818,
"language": "en",
"is_pinned": false,
"liked_by_creator": false,
"parent_id": "",
"reply_to_id": "",
"author": {
"id": "7000000000000000001",
"username": "example_commenter",
"nickname": "Example Commenter",
"avatar": "https://p16-common-sign.tiktokcdn-us.com/…",
"verified": false,
"sec_uid": "MS4wLjABAAAA…",
"url": "https://www.tiktok.com/@example_commenter",
"stats": null
}
}
]
}
total is TikTok's count of all comments on the video, replies included, so it's higher than the number of top-level comments you'll collect.
Save as you go
Open the CSV first and write each page to it as soon as it arrives. If a request fails for good later, for example because your plan's quota ran out, the script stops with an error but the file keeps every comment collected before it.
FIELDS = ["id", "parent_id", "reply_to_id", "created_at", "likes", "reply_count",
"language", "liked_by_creator", "is_pinned", "username", "text"]
out = open(f"comments_{video}.csv", "w", newline="", encoding="utf-8")
writer = csv.DictWriter(out, fieldnames=FIELDS, extrasaction="ignore")
writer.writeheader()
def save(rows):
"""Write rows to the CSV right away, so a later error can't lose them."""
for c in rows:
writer.writerow({**c, "username": (c.get("author") or {}).get("username", "")})
out.flush()
Rows with an empty parent_id are top-level comments; the others are replies.
Get the comments
Pass next_cursor back as cursor while has_more is true. Each page is one request, and max_pages caps how many the loop makes: 5 pages are about 200 comments.
def collect(path, max_pages):
"""Follow next_cursor for up to max_pages requests, saving each page."""
rows, cursor = [], None
for _ in range(max_pages):
params = {"cursor": cursor} if cursor else {}
data = get(path, **params)
page = data.get("comments") or []
save(page)
rows.extend(page)
cursor = data.get("next_cursor")
if not data.get("has_more") or not cursor:
break
return rows
top_level = collect(f"/v1/tiktok/videos/{video}/comments", max_pages=5)
print(len(top_level), "comments")
Add the replies
Replies live under each comment. Fetch them only for comments with reply_count above 0; each page is one request. In a reply, parent_id is the top-level comment and reply_to_id is the reply it answers (empty when it answers the top-level comment).
all_rows = list(top_level)
most_replied = sorted(top_level, key=lambda c: c["reply_count"], reverse=True)[:5]
for c in most_replied:
if c["reply_count"]:
path = f"/v1/tiktok/videos/{video}/comments/{c['id']}/replies"
all_rows.extend(collect(path, max_pages=2))
out.close()
print(len(all_rows), "rows saved")
This reads up to 2 pages of replies for the 5 most-replied comments: at most 10 requests. With the 5 comment pages, the whole script makes at most 15 requests. On a paid plan, raise both max_pages values and the number of threads; big videos have thousands of replies.
Quick analysis
# Most-liked comments
for c in sorted(top_level, key=lambda c: c["likes"], reverse=True)[:5]:
print(c["likes"], c["text"][:100])
# Which languages the audience writes in
print(Counter(c.get("language") or "?" for c in all_rows).most_common(5))
# Comments the creator liked
print(sum(c["liked_by_creator"] for c in top_level), "liked by the creator")
Things to know
- Page size. TikTok returns fewer comments per page than requested: usually 33–42. Reply pages vary in size too.
- Order. Comments come in TikTok's order, not by time. Sort by
created_atorlikesyourself. - Deep threads. Stop on
has_more. On videos with very many comments, TikTok may end the list beforetotalis reached. - Deleted video:
404. A video with no comments returns an empty page. - Freshness. Pages are cached for up to 24 hours.
- Commenters are people.
authorholds their public handle and avatar (itsstatsis alwaysnull). Keep only what your use case needs, and follow the privacy law that applies to you, such as GDPR or CCPA. - This API is unofficial and not affiliated with TikTok.
Next steps
- List a creator's videos, then collect comments on each one.
- Find videos by hashtag or by keyword to study comments across a topic.
- API docs for all 13 endpoints.
Plans
Every page of comments or replies is one request; the script above makes at most 15. A free plan covers testing. Plans, monthly quotas and rate limits are listed on the RapidAPI listing. For more volume or a custom plan, use Contact provider on the listing.