Search TikTok videos by keyword and export them to CSV with Python
Run a TikTok search for a few keywords, merge the results, keep the videos from the last 30 days and save them to a CSV file. Then rank them by engagement and list the creators behind them. One request returns up to 20 videos.
Keyword search is where most TikTok research starts: what gets posted about a product, a trend in a niche, which creators own a topic. TikTok's official APIs don't offer search for commercial use; the Research API is for academic and not-for-profit research only. The TikTok Video & Creator API returns TikTok's public search results as JSON, and every video already carries its creator and sound, so one search doubles as a creator finder.
Setup
You need Python 3, requests (pip install requests) and a key from the RapidAPI listing; the free plan's 100 requests are enough to try it. Put the key in an environment variable called RAPIDAPI_KEY. The example below (2 keywords, up to 3 pages each) makes at most 6 requests.
import csv
import os
import time
from datetime import datetime, timedelta, timezone
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()
Search one page
GET /v1/tiktok/search/videos takes q (1–100 characters; hashtags like #skincare work too) and returns up to 20 videos.
curl --request GET \
--url 'https://tiktok-video-creator-api.p.rapidapi.com/v1/tiktok/search/videos?q=street%20food' \
--header "X-RapidAPI-Key: $RAPIDAPI_KEY" \
--header 'X-RapidAPI-Host: tiktok-video-creator-api.p.rapidapi.com'
Real response for q=street food from 2026-09-24, one of 20 videos shown, media links shortened
{
"query": "street food",
"count": 20,
"has_more": true,
"next_cursor": "MjA6MjAyNjA5MjQyMTAxMjI2NTlEMjFEMzlGNTQ4MTJGMTdDMA",
"videos": [
{
"id": "7688378448947055885",
"url": "https://www.tiktok.com/@kimnlizasmr/video/7688378448947055885",
"description": "Eating only Korean street foods for a full day when this happened… #food #eating #mukbang #streetfood #korea ",
"created_at": "2026-09-22T15:15:18Z",
"duration": 62,
"width": 720,
"height": 1280,
"is_photo_post": false,
"is_pinned": false,
"is_ad": false,
"cover": "https://p16-common-sign.tiktokcdn-us.com/…",
"dynamic_cover": "https://p16-common-sign.tiktokcdn-us.com/…",
"play_url": "https://v16-webapp-prime.us.tiktok.com/…",
"images": [],
"hashtags": ["food", "eating", "mukbang", "streetfood", "korea"],
"stats": { "plays": 685200, "likes": 53800, "comments": 211, "shares": 1257, "bookmarks": 2766 },
"author": {
"id": "6699037984631473157",
"username": "kimnlizasmr",
"nickname": "Kimlizasmr",
"avatar": "https://p16-common-sign.tiktokcdn-us.com/…",
"verified": false,
"sec_uid": "MS4wLjABAAAAR_i0OQn_UuZc6oCZ2ChfIYkBVlQdxLhdE4lCXC2nxPvN1LCPP9Ombt-DmWAS39NJ",
"url": "https://www.tiktok.com/@kimnlizasmr",
"stats": { "followers": 7200000, "following": 22, "likes": 263900000, "videos": 1901, "friends": 0 }
},
"music": {
"id": "7675014190469335838",
"title": "original sound",
"author": "prettylittlepryncess",
"original": true,
"duration": 12,
"cover": "https://p16-common-sign.tiktokcdn-us.com/…",
"play_url": "https://v16-webapp-prime.us.tiktok.com/…"
}
}
]
}
The creator (author, with follower counts) and the sound (music) come with every video, so you don't need extra calls for them.
More keywords and pages
Pass next_cursor back unchanged as cursor for the next page, and stop when has_more is false. One video can match two keywords, so key the results by video id.
def search(query, max_pages=3):
videos, cursor = [], None
for _ in range(max_pages):
params = {"q": query}
if cursor:
params["cursor"] = cursor
data = get("/v1/tiktok/search/videos", **params)
videos.extend(data.get("videos") or [])
cursor = data.get("next_cursor")
if not data.get("has_more") or not cursor:
break
return videos
KEYWORDS = ["street food", "korean street food"]
found = {}
for keyword in KEYWORDS:
for v in search(keyword):
found.setdefault(v["id"], {**v, "keyword": keyword})
videos = list(found.values())
print(len(videos), "unique videos")
Keep the recent ones
Results come in TikTok's relevance order, not by date, and include older hits. Filter on created_at (UTC):
cutoff = datetime.now(timezone.utc) - timedelta(days=30)
recent = [v for v in videos
if datetime.fromisoformat(v["created_at"].replace("Z", "+00:00")) >= cutoff]
print(len(recent), "from the last 30 days")
Save a CSV
FIELDS = ["id", "created_at", "keyword", "plays", "likes", "comments", "shares",
"bookmarks", "duration", "username", "followers", "hashtags", "url", "description"]
with open("tiktok_search.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
for v in recent:
author = v["author"]
writer.writerow({
"id": v["id"],
"created_at": v["created_at"],
"keyword": v["keyword"],
**{k: v["stats"][k] for k in ("plays", "likes", "comments", "shares", "bookmarks")},
"duration": v["duration"],
"username": author["username"],
"followers": (author.get("stats") or {}).get("followers", ""),
"hashtags": " ".join(v["hashtags"]),
"url": v["url"],
"description": v["description"].strip(),
})
The row for the video above
7688378448947055885,2026-09-22T15:15:18Z,street food,685200,53800,211,1257,2766,62,kimnlizasmr,7200000,food eating mukbang streetfood korea,https://www.tiktok.com/@kimnlizasmr/video/7688378448947055885,Eating only Korean street foods for a full day when this happened… #food #eating #mukbang #streetfood #korea
Rank videos and creators
Engagement rate here is likes, comments, shares and bookmarks divided by plays. It shows which videos hold attention, whatever the creator's size. The creator list sums plays per account across your results.
def engagement(v):
s = v["stats"]
return (s["likes"] + s["comments"] + s["shares"] + s["bookmarks"]) / max(s["plays"], 1)
for v in sorted(recent, key=engagement, reverse=True)[:10]:
print(f'{engagement(v):.1%} {v["stats"]["plays"]:>11,} plays @{v["author"]["username"]} {v["url"]}')
creators = {}
for v in recent:
a = v["author"]
c = creators.setdefault(a["username"], {
"followers": (a.get("stats") or {}).get("followers", 0), "videos": 0, "plays": 0})
c["videos"] += 1
c["plays"] += v["stats"]["plays"]
for name, c in sorted(creators.items(), key=lambda kv: kv[1]["plays"], reverse=True)[:10]:
print(f'@{name}: {c["followers"]:,} followers, {c["plays"]:,} plays in {c["videos"]} result(s)')
The lines the video above gets
8.5% 685,200 plays @kimnlizasmr https://www.tiktok.com/@kimnlizasmr/video/7688378448947055885
@kimnlizasmr: 7,200,000 followers, 685,200 plays in 1 result(s)
To dig into a creator you found, call GET /v1/tiktok/users/{username} for the exact profile counts and GET /v1/tiktok/users/{username}/videos for their posts (see the user videos guide). To search for accounts by keyword directly, use GET /v1/tiktok/search/users?q= (up to 10 per page).
Things to know
- Refused keywords. A keyword TikTok itself won't search (adult, drug or self-harm terms) returns an empty page (
count: 0), as on TikTok. It isn't an error. - Relevance order. Results come in TikTok's order. Sort and filter by
created_atorstatsyourself. - Rounded counts. Counts inside videos are the values TikTok ships with the post, rounded for large numbers (7,200,000 followers). For a creator's exact counts, use the profile endpoint.
- Freshness. Answers are cached for up to 24 hours. Search cursors keep working later, so you can store them and continue.
- Media links (
cover,play_url,avatar) expire after a few hours.play_urlis TikTok's playback link, not a download service. - Errors:
400missing or invalidqorcursor,429plan limit,502TikTok failed after our retries (thegethelper retries it). - This API is unofficial and not affiliated with TikTok. It reads public data only; no TikTok login is needed.
Next steps
- Get the videos for a hashtag, with its total view count.
- Collect the comments on the top videos.
- Track the creators you found every day.
- No code? Run the TikTok Video Search Actor on Apify: it collects the videos TikTok shows for your keywords and exports them to CSV or Excel.
Plans
Every search page of up to 20 videos is one request. 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.