TikTok's developer products, from Login Kit to the Research API, include nothing for LIVE: no call returns a stream, its viewers or its gifts. Our TikTok API reads the public LIVE data the app shows: rooms for a search term, and whether a creator is live now.
What TikTok's developer platform offers
TikTok's products page lists tools for signing in with TikTok, sharing and posting to a user's own account, embedding videos, and exporting a user's own data in the EEA and UK. The Display API reads the videos of a user who signs in to your app, and the Research API is closed to creators, advertisers and other commercial users. The page never mentions LIVE.
LIVE data with ToolzerHub
We make ToolzerHub. Our TikTok API returns public TikTok profiles, videos, sounds and LIVE rooms as JSON with one API key. These routes do the job here:
/v2/tiktok/app/search/live: live rooms for akeyword, about 20 a call; passcursorasoffsetfor the next page, 2 credits/v2/tiktok/web/user/live: a creator's current or last room by handle, with viewers and start time, 2 credits/v2/tiktok/app/live/room: one room's details byroom_id, 2 credits
export TOOLZERHUB_API_KEY=your_key
curl -H "x-api-key: $TOOLZERHUB_API_KEY" \
"https://api.toolzerhub.com/v2/tiktok/app/search/live?keyword=music"
Results in data.data mix accounts with live rooms. A room is type 1, and its details sit in lives.rawdata, a JSON string, parsed and trimmed here:
{
"type": 1,
"lives": {
"author": {"unique_id": "troystarrmusic", "room_id_str": "7704408845073877773"},
"rawdata": {
"id_str": "7704408845073877773",
"title": "Lets Go LIVE!",
"user_count": 62,
"stats": {"total_user": 1609},
"like_count": 60041,
"start_time": 1793822566,
"hashtag": {"title": "Music"},
"owner": {"follow_info": {"follower_count": 17264}}
}
}
}
user_count is the current viewer count: minutes later the same room showed 66 on /web/user/live. stats.total_user counts joins since start_time, in Unix seconds, and this room had been live 76 minutes. hashtag.title is the room's LIVE category. To check one creator, pass the handle to /web/user/live: status 2 means live, with liveRoomStats.userCount, and status 4 means not live, with the last room's title. We don't cover LIVE chat: our chat route returned no messages for the two rooms we tried.
Find live rooms for a topic
The script searches each term, reads the pages you ask for, keeps each room once and writes one row per room with its host, followers, title, category, viewers now, total viewers, likes and minutes live. For each term it prints the median viewers, how many rooms have under 10 and the longest stream. Install requests (pip install requests) and save it as tiktok_live.py.
import csv
import json
import os
import statistics
import sys
import time
import requests
API = "https://api.toolzerhub.com/v2/tiktok/app/search/live"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["keyword", "room_id", "host", "followers", "title", "category", "viewers_now", "viewers_total", "likes",
"minutes_live", "url"]
def get(params, tries=3):
# Retry rate limits, server errors and dropped connections.
for attempt in range(tries):
last = attempt == tries - 1
try:
r = requests.get(API, headers=HEADERS, params=params, timeout=120)
except requests.RequestException:
if last:
raise
time.sleep(5 * (attempt + 1))
continue
if r.status_code in (429, 500, 502, 503, 504) and not last:
time.sleep(5 * (attempt + 1))
continue
r.raise_for_status()
return r.json()["data"]
def main(keywords, pages="2", out="tiktok_live.csv"):
with open(out, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
for keyword in filter(None, (k.strip() for k in keywords.split(","))):
rooms, seen, offset = [], set(), 0
for _ in range(int(pages)):
data = get({"keyword": keyword, "offset": offset})
# Results mix live rooms (type 1) with accounts; each room's details are a JSON string.
for item in data.get("data") or []:
if item.get("type") != 1:
continue
raw = item["lives"]["rawdata"]
room = json.loads(raw) if isinstance(raw, str) else raw
if room["id_str"] not in seen:
seen.add(room["id_str"])
rooms.append((item["lives"]["author"], room))
if not data.get("has_more"):
break
offset = data["cursor"]
now = time.time()
for author, room in rooms:
writer.writerow({
"keyword": keyword, "room_id": room["id_str"], "host": author["unique_id"],
"followers": (room.get("owner") or {}).get("follow_info", {}).get("follower_count"),
"title": room.get("title"), "category": (room.get("hashtag") or {}).get("title"),
"viewers_now": room.get("user_count"), "viewers_total": (room.get("stats") or {}).get("total_user"),
"likes": room.get("like_count"), "minutes_live": round((now - room["start_time"]) / 60),
"url": f"https://www.tiktok.com/@{author['unique_id']}/live",
})
viewers = [room.get("user_count") or 0 for _, room in rooms]
hours = [(now - room["start_time"]) / 3600 for _, room in rooms]
print(f"{keyword}: {len(rooms)} live rooms, median {statistics.median(viewers or [0]):,.0f} viewers now, "
f"{sum(v < 10 for v in viewers)} under 10, longest live {max(hours or [0]):.1f} hours")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit('usage: python tiktok_live.py "music,cooking" [pages] [out.csv]')
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
What four topics showed
python tiktok_live.py "music,gaming,cooking,fitness" 3 made 12 calls in 49 seconds on a weekday evening, European time, and saved 214 live rooms.
| Search term | Live rooms read | Median viewers now | Under 10 viewers | 1,000 viewers or more | Top 5 rooms' share of viewers | Median minutes live |
|---|---|---|---|---|---|---|
| music | 50 | 48.5 | 6 | 0 | 42% | 95 |
| gaming | 47 | 519 | 0 | 12 | 35% | 89 |
| cooking | 59 | 4 | 40 | 0 | 74% | 52 |
| fitness | 58 | 40.5 | 11 | 1 | 55% | 106.5 |
Gaming was the only topic where every room had 10 or more viewers, and 12 of its 47 rooms had 1,000 or more. One gaming host had been live for 34.1 hours, "PLAYING EVERY GOD OF WAR GAME!!!". Cooking was the opposite: 40 of 59 rooms had under 10 viewers, and the five biggest held 74% of everyone watching.
Search matches titles loosely, so check the category. The busiest "cooking" room was "Viiibrations: Cook Out" in the Music category, and 53 of the 59 cooking rooms had no category. The "fitness" results included two trading-card shops, blacktiecardshop and blacktiebreaks, streaming product releases.
What it costs
Search is 2 credits a call, so a topic at three pages is 6 credits and a live check on one creator is 2. The 100 free credits a month cover 16 topics at that depth or 50 live checks; $19 buys 10,000 credits that never expire, and plans for higher volume cover checking rooms every few minutes. Set your key and the first topic is a CSV in under a minute.
For the videos behind a sound, see the TikTok sound API. For keyword search over videos, see the TikTok search API.
We are not affiliated with TikTok or ByteDance.