Liveness probe — returns service name and server time.
curl -s "$BASE/api/health"
{
"status": "ok",
"app": "TikTokScope",
"time": 1760000000
}
A read-only JSON API for public TikTok and Douyin data — profiles, followers, videos, comments, hashtags, sounds, live status and keyword search. No API key, no third-party scraping vendor. Every route is served from the same origin as this page.
https://tiktokscope.120319.xyz
— same origin, so all routes below are relative (/api/…).
Set BASE to the origin you are calling (the site that serves this page),
then hit any route. Responses are JSON unless noted otherwise; CSV exports stream as
text/csv attachments.
# All paths are relative to the serving origin.
export BASE="https://tiktokscope.120319.xyz"
# 1. Liveness — cheapest way to verify the API is up.
curl -s "$BASE/api/health" | jq
# 2. A profile record.
curl -s "$BASE/api/profile/charlidamelio" | jq
# 3. The first page of that account's followers.
curl -s "$BASE/api/followers/charlidamelio?cursor=0&count=20" | jq '.users[0]'
# 4. A video plus its engagement stats.
curl -s "$BASE/api/video?url=https://www.tiktok.com/@charlidamelio/video/7300000000000000000" | jq
GET and read-only. Errors are returned as
{"detail": "…"} with HTTP 400 (bad input), 404 (not found),
502 (upstream scrape failure) or 500 (unexpected).
Liveness probe — returns service name and server time.
curl -s "$BASE/api/health"
{
"status": "ok",
"app": "TikTokScope",
"time": 1760000000
}
Service status with the running release and uptime. This is the source the header version badge is read from.
curl -s "$BASE/api/status"
{
"status": "ok",
"app": "TikTokScope",
"version": "3.1.0",
"uptime_seconds": 128934,
"time": 1760000000
}
Readiness probe — verifies the SQLite cache and the Node signer used for signed search are usable.
curl -s "$BASE/api/ready"
{
"status": "ok",
"checks": {
"db": "ok",
"signer": "ok"
}
}
The most recent lookups recorded by the server (profiles, videos, hashtags, exports).
curl -s "$BASE/api/history"
{
"items": [
{
"kind": "profile",
"query": "charlidamelio",
"summary": "charli d'amelio",
"created_at": 1760000000.12
},
{
"kind": "video",
"query": "https://www.tiktok.com/@charlidamelio/video/7300000000000000000",
"summary": "day in the life #fyp",
"created_at": 1759999800.44
},
{
"kind": "hashtag",
"query": "fyp",
"summary": "321000000 videos",
"created_at": 1759999500.03
}
]
}
Full public profile record: identity, bio, verification and lifetime counters.
Path: username — handle with or without a leading @.
curl -s "$BASE/api/profile/charlidamelio"
{
"username": "charlidamelio",
"nickname": "charli d'amelio",
"user_id": "5831967",
"sec_uid": "MS4wLjABAAAA7Q8Yw2m9...",
"bio": "hi",
"verified": true,
"private": false,
"region": "US",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"followers": 155400000,
"following": 1200,
"likes": 11500000000,
"videos": 2400
}
Aggregated engagement metrics for the account's recent videos, plus per-video breakdowns.
Path: username. Query: limit (int, recent videos to score).
curl -s "$BASE/api/profile/charlidamelio/analytics"
{
"username": "charlidamelio",
"generated_at": 1760000000,
"profile": {
"followers": 155400000,
"following": 1200,
"likes": 11500000000,
"videos": 2400
},
"recent_videos": [
{
"id": "7300000000000000000",
"desc": "day in the life #fyp",
"stats": {
"plays": 2500000,
"likes": 340000,
"comments": 4200,
"shares": 18000,
"collects": 9600
},
"metrics": {
"engagement_rate": 0.1449,
"save_rate": 0.0038,
"share_rate": 0.0072,
"comment_rate": 0.0017,
"like_rate": 0.136,
"like_per_1k": 136.0,
"amplification": 0.0812,
"est_watch_proxy": 2.1735
}
}
],
"averages": {
"engagement_rate": 0.121,
"save_rate": 0.0031,
"share_rate": 0.0056,
"comment_rate": 0.0014,
"like_per_1k": 118.7,
"amplification": 0.0742
}
}
Resolve many profiles in one request; failures are reported per row rather than aborting the batch.
Query: users — comma-separated handles (e.g. a,b,c).
curl -s "$BASE/api/batch/profiles?users=charlidamelio,khaby.lame,ghost_user"
{
"count": 3,
"results": [
{
"username": "charlidamelio",
"nickname": "charli d'amelio",
"verified": true,
"followers": 155400000,
"following": 1200,
"likes": 11500000000,
"videos": 2400,
"error": null
},
{
"username": "khaby.lame",
"nickname": "Khabane lame",
"verified": true,
"followers": 162800000,
"following": 48,
"likes": 2400000000,
"videos": 1100,
"error": null
},
{
"username": "ghost_user",
"nickname": null,
"verified": false,
"followers": null,
"following": null,
"likes": null,
"videos": null,
"error": "No user data for @ghost_user"
}
]
}
Leaderboard of the most-followed creators currently tracked by the server, resolved to live profile cards.
Query: count (1–50, default 20).
curl -s "$BASE/api/creators/top?count=20"
{
"items": [
{
"username": "khaby.lame",
"nickname": "Khabane lame",
"sec_uid": "MS4wLjABAAAA...",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": true
},
{
"username": "charlidamelio",
"nickname": "charli d'amelio",
"sec_uid": "MS4wLjABAAAA...",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": true
}
]
}
Keyword search is signed server-side with the vendored Node signer. Analytics and benchmarking are computed from cached video records using the metrics defined below.
General keyword search across videos and users. Videos are returned with derived metrics; non-video, non-user hits are counted in other_results.
Query: q (required), cursor (int, default 0), count (1–30, default 12).
curl -s "$BASE/api/search?q=cooking&count=12"
{
"query": "cooking",
"cursor": 12,
"has_more": true,
"videos": [
{
"id": "7300000000000000000",
"desc": "easy 15-minute pasta #foodtok",
"create_time": 1699000000,
"duration": 22,
"author": {
"username": "chefanna",
"nickname": "Anna Cooks",
"sec_uid": "MS4wLjABAAAA...",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": false
},
"stats": {
"plays": 820000,
"likes": 91000,
"comments": 1400,
"shares": 6200,
"collects": 12000,
"reposts": 300
},
"metrics": {
"engagement_rate": 0.1202,
"save_rate": 0.0146,
"share_rate": 0.0076,
"comment_rate": 0.0017,
"like_rate": 0.111,
"like_per_1k": 111.0,
"amplification": 0.0769,
"est_watch_proxy": 2.6444
},
"music": "original sound",
"music_id": "7000000000000000000",
"challenges": ["foodtok", "pasta"]
}
],
"users": [
{
"username": "chefanna",
"nickname": "Anna Cooks",
"sec_uid": "MS4wLjABAAAA...",
"signature": "recipes every day",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": false
}
],
"other_results": 1
}
Keyword search restricted to user accounts. Each hit is a lightweight profile card.
Query: q (required), cursor (int, default 0), count (1–30, default 12).
curl -s "$BASE/api/search/users?q=charli"
{
"query": "charli",
"cursor": 12,
"has_more": true,
"users": [
{
"username": "charlidamelio",
"nickname": "charli d'amelio",
"sec_uid": "MS4wLjABAAAA...",
"signature": "hi",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": true
}
]
}
Photo (image-post) search. Each result is a video record whose images array holds the slide URLs; derived metrics are attached as usual.
Query: q (required), cursor (int, default 0), count (1–30, default 12).
curl -s "$BASE/api/search/photos?q=sunset&count=12"
{
"query": "sunset",
"items": [
{
"id": "7300000000000000001",
"desc": "golden hour #sunset",
"create_time": 1699000000,
"duration": 0,
"author": {
"username": "skylover",
"nickname": "Sky Lover",
"sec_uid": "MS4wLjABAAAA...",
"verified": false
},
"stats": {
"plays": 410000,
"likes": 52000,
"comments": 610,
"shares": 2400,
"collects": 8800,
"reposts": 120
},
"metrics": {
"engagement_rate": 0.1342,
"save_rate": 0.0215,
"share_rate": 0.0059,
"comment_rate": 0.0015,
"like_rate": 0.1268,
"like_per_1k": 126.8,
"amplification": 0.2154,
"est_watch_proxy": null
},
"images": [
["https://p16-sign.tiktokcdn-us.com/...1.jpg"],
["https://p16-sign.tiktokcdn-us.com/...2.jpg"]
],
"challenges": ["sunset"]
}
],
"has_more": true,
"next_cursor": 12
}
Hashtag/challenge search. Returns matching tags with their lifetime view and video counts.
Query: q (required).
curl -s "$BASE/api/search/hashtags?q=fy"
{
"query": "fy",
"items": [
{ "tag": "fyp", "views": 59800000000000, "videos": 321000000 },
{ "tag": "foryou", "views": 41200000000000, "videos": 214000000 },
{ "tag": "foryoupage", "views": 18900000000000, "videos": 98000000 }
]
}
Sound/music search. Each item describes a track and how many videos use it.
Query: q (required).
curl -s "$BASE/api/search/sounds?q=original%20sound"
{
"query": "original sound",
"items": [
{
"music_id": "7000000000000000000",
"title": "original sound",
"author": "chefanna",
"duration": 24,
"video_count": 125000,
"cover": "https://p16-sign.tiktokcdn-us.com/..."
}
]
}
A creator's public video list, unsigned and paginated. Items carry derived metrics.
Path: username. Query: cursor (int, default 0), count (1–19, default 15).
curl -s "$BASE/api/profile/charlidamelio/videos?cursor=0&count=15"
{
"username": "charlidamelio",
"items": [
{
"id": "7300000000000000000",
"desc": "day in the life #fyp",
"create_time": 1699000000,
"duration": 15,
"author": {
"username": "charlidamelio",
"nickname": "charli d'amelio",
"sec_uid": "MS4wLjABAAAA..."
},
"stats": {
"plays": 2500000,
"likes": 340000,
"comments": 4200,
"shares": 18000,
"collects": 9600,
"reposts": 180
},
"metrics": {
"engagement_rate": 0.1449,
"save_rate": 0.0038,
"share_rate": 0.0072,
"comment_rate": 0.0017,
"like_rate": 0.136,
"like_per_1k": 136.0,
"amplification": 0.0812,
"est_watch_proxy": 2.1735
}
}
],
"has_more": true,
"next_cursor": 15
}
Videos a creator has reposted, newest first, in the same shape as the video list.
Path: username. Query: cursor (int, default 0), count (1–30, default 20).
curl -s "$BASE/api/profile/charlidamelio/reposts?count=20"
{
"username": "charlidamelio",
"items": [
{
"id": "7300000000000000009",
"desc": "this edit #fyp",
"create_time": 1698990000,
"duration": 11,
"author": {
"username": "editor.friend",
"nickname": "editor",
"sec_uid": "MS4wLjABAAAA..."
},
"stats": {
"plays": 540000,
"likes": 76000,
"comments": 900,
"shares": 4100,
"collects": 5200,
"reposts": 640
},
"metrics": {
"engagement_rate": 0.1519,
"save_rate": 0.0096,
"share_rate": 0.0076,
"comment_rate": 0.0017,
"like_rate": 0.1407,
"like_per_1k": 140.7,
"amplification": 0.1224,
"est_watch_proxy": 1.6709
}
}
],
"has_more": false,
"next_cursor": 20
}
Samples a creator's recent videos and groups their engagement rate by weekday/hour (UTC), plus a duration-bucket curve.
Path: username. Query: limit (4–20, default 12).
curl -s "$BASE/api/profile/charlidamelio/best-time?limit=12"
{
"username": "charlidamelio",
"sampled": 12,
"best_times": [
{ "weekday": 2, "hour": 18, "videos": 3, "avg_engagement_rate": 0.1421 },
{ "weekday": 5, "hour": 20, "videos": 2, "avg_engagement_rate": 0.1318 }
],
"duration_curve": [
{ "bucket": "0-15s", "videos": 4, "avg_engagement_rate": 0.1611 },
{ "bucket": "15-30s", "videos": 5, "avg_engagement_rate": 0.1204 },
{ "bucket": "30-60s", "videos": 3, "avg_engagement_rate": 0.0982 },
{ "bucket": "60s+", "videos": 0, "avg_engagement_rate": null }
]
}
Compare up to four creators side by side. Each creator's recent videos are sampled to produce comparable rows.
Query: users — comma-separated handles; videos (3–12, default 4) sampled per creator.
curl -s "$BASE/api/benchmark?users=charlidamelio,khaby.lame&videos=4"
{
"rows": [
{
"username": "khaby.lame",
"nickname": "Khabane lame",
"followers": 162800000,
"following": 48,
"likes_total": 2400000000,
"videos_total": 1100,
"sampled_videos": 4,
"avg_engagement_rate": 0.1564,
"avg_plays": 4200000,
"plays_per_follower": 0.0258,
"posts_last_30d": 2,
"avg_days_between_posts": 4.2
},
{
"username": "charlidamelio",
"nickname": "charli d'amelio",
"followers": 155400000,
"following": 1200,
"likes_total": 11500000000,
"videos_total": 2400,
"sampled_videos": 4,
"avg_engagement_rate": 0.121,
"avg_plays": 1800000,
"plays_per_follower": 0.0116,
"posts_last_30d": 3,
"avg_days_between_posts": 2.7
}
]
}
Ranked trending search terms for a region.
Query: region (two-letter code, default US).
curl -s "$BASE/api/tiktok/trending-searches?region=US"
{
"items": [
{ "rank": 1, "word": "fyp", "type": 1 },
{ "rank": 2, "word": "summer", "type": 1 },
{ "rank": 3, "word": "recipe", "type": 2 }
]
}
Native description and subtitle translation for a video.
Query: url or id (+ optional author), lang (default es).
curl -s "$BASE/api/video/transcript?url=https://www.tiktok.com/@charlidamelio/video/7300000000000000000&lang=es"
{
"id": "7300000000000000000",
"target": "es",
"description": "día en la vida #fyp",
"subtitle": "hola chicos\nbienvenidos de nuevo a mi canal"
}
One page of a user's follower list, with the profile header included.
Path: username. Query: cursor (int, default 0), count (1–50, default 20).
curl -s "$BASE/api/followers/charlidamelio?cursor=0&count=20"
{
"profile": {
"username": "charlidamelio",
"nickname": "charli d'amelio",
"sec_uid": "MS4wLjABAAAA7Q8Yw2m9...",
"followers": 155400000
},
"users": [
{
"user_id": "6901234567890123456",
"username": "somefan",
"nickname": "Some Fan",
"sec_uid": "MS4wLjABAAAA...",
"bio": "fan account",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": false,
"private": false,
"followers": 1234,
"following": 321,
"likes": 5678,
"videos": 42
}
],
"total": 155400000,
"has_more": true,
"next_cursor": 20
}
Stream the follower list as a downloadable CSV, paginating upstream automatically.
Path: username. Query: limit (1–5000, default 500).
curl -s "$BASE/api/followers/charlidamelio/export?limit=500" -o charli-followers.csv
user_id,username,nickname,sec_uid,bio,verified,private,followers,following,likes,videos
6901234567890123456,somefan,Some Fan,MS4wLjABAAAA...,fan account,False,False,1234,321,5678,42
6901234567890123457,anotherfan,Another Fan,MS4wLjABAAAA...,,False,True,88,120,301,7
...
Full video record: author, lifetime stats, media URLs, music, hashtags and subtitle tracks.
Query: url (canonical video URL) or id + author.
# By URL
curl -s "$BASE/api/video?url=https://www.tiktok.com/@charlidamelio/video/7300000000000000000"
# Or by bare id + author
curl -s "$BASE/api/video?id=7300000000000000000&author=charlidamelio"
{
"id": "7300000000000000000",
"desc": "day in the life #fyp",
"create_time": 1699000000,
"duration": 15,
"author": {
"username": "charlidamelio",
"nickname": "charli d'amelio",
"sec_uid": "MS4wLjABAAAA7Q8Yw2m9...",
"avatar": "https://p16-sign.tiktokcdn-us.com/...",
"verified": true
},
"stats": {
"plays": 2500000,
"likes": 340000,
"comments": 4200,
"shares": 18000,
"collects": 9600
},
"cover": "https://p16-sign.tiktokcdn-us.com/...",
"play_url": "https://v16-webapp.tiktokcdn.com/...mp4",
"download_url": "https://v16-webapp.tiktokcdn.com/...mp4",
"music": "original sound",
"music_id": "7000000000000000000",
"music_author": "charlidamelio",
"subtitles": [
{ "lang": "eng-US", "format": "webvtt", "url": "https://.../subtitle.vtt" }
],
"challenges": ["fyp", "dayinthelife"]
}
Clean anonymous video-detail fallback (useful when the main record is gated); includes subtitle URLs.
Query: url or id.
curl -s "$BASE/api/video/reflow?id=7300000000000000000"
{
"id": "7300000000000000000",
"desc": "day in the life #fyp",
"create_time": 1699000000,
"author": {
"username": "charlidamelio",
"nickname": "charli d'amelio",
"sec_uid": "MS4wLjABAAAA7Q8Yw2m9..."
},
"stats": {
"plays": 2500000,
"likes": 340000,
"comments": 4200,
"shares": 18000
},
"music": "original sound",
"music_id": "7000000000000000000",
"cover": null,
"play_url": null,
"download_url": null,
"subtitles": [
{ "lang": "eng-US", "format": "webvtt", "url": "https://.../subtitle.vtt" }
],
"challenges": ["fyp"]
}
Parsed caption lines for a video, as an array and as a single joined string.
Query: url or id (+ optional author), lang (default eng-US).
curl -s "$BASE/api/video/subtitles?url=https://www.tiktok.com/@charlidamelio/video/7300000000000000000&lang=eng-US"
{
"lines": [
"hey guys",
"welcome back to my channel",
"today we are doing something fun"
],
"text": "hey guys\nwelcome back to my channel\ntoday we are doing something fun"
}
Proxy a TikTok CDN media URL as an MP4 attachment. Non-TikTok hosts are refused.
Query: url — a tiktokcdn, tiktokv or tiktok.com media URL.
curl -s "$BASE/api/download?url=https://v16-webapp.tiktokcdn.com/...mp4" -o tiktok.mp4
HTTP/1.1 200 OK
content-type: video/mp4
content-disposition: attachment; filename="tiktok.mp4"
<binary mp4 bytes>
Recommended videos for a creator, served from the embed feed endpoint. Use sec_uid when you already have it, otherwise pass a username to resolve it first.
Query: username or sec_uid, cursor (int, default 0), count (1–50, default 20).
curl -s "$BASE/api/feed?username=charlidamelio&count=20"
{
"items": [
{
"id": "7300000000000000000",
"desc": "day in the life #fyp",
"author": "charlidamelio",
"plays": 2500000,
"likes": 340000,
"comments": 4200,
"cover": "https://p16-sign.tiktokcdn-us.com/..."
}
],
"has_more": true,
"next_cursor": 20
}
Hashtag/challenge stats: title, description and lifetime view/video counts.
Path: tag — with or without a leading #.
curl -s "$BASE/api/hashtag/fyp"
{
"id": "2284",
"title": "fyp",
"desc": "",
"views": 59800000000000,
"videos": 321000000
}
A page of top videos for a hashtag/challenge, with derived metrics.
Path: name — with or without a leading #. Query: cursor (int, default 0), count (1–50, default 20).
curl -s "$BASE/api/hashtag/fyp/videos?cursor=0&count=20"
{
"query": "fyp",
"videos": [
{
"id": "7300000000000000000",
"desc": "wait for it… #fyp",
"create_time": 1699000000,
"duration": 18,
"author": {
"username": "viraluser",
"nickname": "Viral User",
"sec_uid": "MS4wLjABAAAA..."
},
"stats": {
"plays": 3100000,
"likes": 480000,
"comments": 5200,
"shares": 26000,
"collects": 14000,
"reposts": 900
},
"metrics": {
"engagement_rate": 0.1649,
"save_rate": 0.0045,
"share_rate": 0.0084,
"comment_rate": 0.0017,
"like_rate": 0.1548,
"like_per_1k": 154.8,
"amplification": 0.0833,
"est_watch_proxy": 2.9682
}
}
],
"has_more": true,
"next_cursor": 20
}
Hashtags related to a given tag, each with an approximate video count.
Path: name — with or without a leading #.
curl -s "$BASE/api/hashtag/fyp/related"
{
"name": "fyp",
"related": [
{ "tag": "foryou", "count": 214000000 },
{ "tag": "viral", "count": 98000000 },
{ "tag": "foryoupage", "count": 98000000 }
]
}
Videos using a sound, paginated. Each item is a full video record.
Path: music_id. Query: cursor (int, default 0), count (1–50, default 20).
curl -s "$BASE/api/sound/7000000000000000000?cursor=0&count=20"
{
"items": [
{
"id": "7300000000000000000",
"desc": "day in the life #fyp",
"author": {
"username": "charlidamelio",
"nickname": "charli d'amelio"
},
"stats": {
"plays": 2500000,
"likes": 340000,
"comments": 4200,
"shares": 18000,
"collects": 9600
},
"music_id": "7000000000000000000"
}
],
"has_more": true,
"next_cursor": 20,
"total": 125000
}
Trending topics and hashtags surfaced by TikTok's discover module.
curl -s "$BASE/api/discover"
{
"items": [
{ "title": "#fyp", "link": "https://www.tiktok.com/tag/fyp" },
{ "title": "#summer", "link": "https://www.tiktok.com/tag/summer" },
{ "title": "#foodtok", "link": "https://www.tiktok.com/tag/foodtok" }
]
}
Douyin (抖音) hot-search leaderboard, ranked with hot values and labels.
curl -s "$BASE/api/douyin/trending"
{
"items": [
{
"rank": 1,
"word": "热歌推荐",
"hot_value": 12345678,
"label": 1,
"cover": "https://p3-sign.douyinpic.com/..."
},
{
"rank": 2,
"word": "夏日穿搭",
"hot_value": 9876543,
"label": null,
"cover": null
}
]
}
Douyin challenge (话题) detail with stats and a page of associated videos.
Path: ch_id. Query: cursor (int, default 0), count (1–50, default 20).
curl -s "$BASE/api/douyin/challenge/1234567890"
{
"id": "1234567890",
"title": "夏日穿搭",
"views": 42000000000,
"videos": 8600000,
"is_commerce": false,
"items": [
{
"id": "7300000000000000000",
"desc": "#夏日穿搭 今天穿这套",
"author": { "username": "dy_user", "nickname": "抖音用户" },
"stats": { "plays": 1200000, "likes": 98000, "comments": 1200, "shares": 5400 }
}
],
"has_more": true,
"next_cursor": 20
}
Douyin (抖音) creator profile by sec_uid, via the public iesdouyin web API.
Path: sec_uid — the Douyin security id.
curl -s "$BASE/api/douyin/profile/MS4wLjABAAAA..."
{
"sec_uid": "MS4wLjABAAAA...",
"username": "dy_user",
"nickname": "抖音用户",
"bio": "记录美好生活",
"avatar": "https://p3-sign.douyinpic.com/...",
"followers": 1234000,
"following": 321,
"likes": 8900000,
"videos": 210,
"verified": false
}
Live-status check for an account, with room metadata and stream URLs when live.
Path: username.
curl -s "$BASE/api/live/charlidamelio"
{
"username": "charlidamelio",
"is_live": true,
"room_id": "7300000000000000000",
"title": "come hang out 💕",
"viewer_count": 48210,
"like_count": 1204500,
"started_at": 1760000000,
"cover": "https://p16-sign.tiktokcdn-us.com/...",
"stream_urls": {
"flv": "https://pull-flv-l1.tiktokcdn.com/...",
"hls": "https://pull-hls-l1.tiktokcdn.com/....m3u8"
}
}
Keyword autocomplete suggestions for search/typeahead.
Query: q — the partial term.
curl -s "$BASE/api/suggest?q=charl"
{
"query": "charl",
"suggestions": [
"charlidamelio",
"charlie puth",
"charlotte tilbury",
"charlie brown"
]
}
Standard oEmbed metadata for a video URL, suitable for link unfurling.
Query: url — the canonical video URL.
curl -s "$BASE/api/oembed?url=https://www.tiktok.com/@charlidamelio/video/7300000000000000000"
{
"version": "1.0",
"type": "video",
"title": "day in the life #fyp",
"author_name": "charli d'amelio",
"author_url": "https://www.tiktok.com/@charlidamelio",
"width": 325,
"height": 570,
"html": "<blockquote class=\"tiktok-embed\" data-video-id=\"7300000000000000000\">…</blockquote>",
"thumbnail_width": 720,
"thumbnail_height": 1280,
"thumbnail_url": "https://p16-sign.tiktokcdn-us.com/..."
}
Added in the current release: direct media/audio, PDF+CSV reports, embeddable cards, Douyin topic videos and deep live rooms.
Direct media URLs from the reflow endpoint: video play/download and the sound audio track.
Query: url or id.
curl -s "$BASE/api/video/media?id=7540092833810730270"
{
"id": "7540092833810730270",
"play_url": "https://v16-webapp.../video/tos/...",
"download_url": "https://v16-webapp.../video/tos/...",
"music": "original sound",
"music_url": "https://...",
"music_duration": 24,
"subtitles": [{ "lang": "eng-US", "format": "webvtt", "url": "..." }]
}
Download a one-page report for a creator. format=csv (default) or format=pdf.
curl -s -o alice.pdf "$BASE/api/report/profile/alice?format=pdf"
Download a report for a video (stats + engagement metrics).
curl -s -o video.csv "$BASE/api/report/video?url=https://www.tiktok.com/@user/video/123&format=csv"
oEmbed-style profile card for embedding. A ready-made widget also lives at /embed?user=username.
{ "type": "rich", "provider_name": "TikTokScope", "title": "@alice on TikTok", "thumbnail_url": "...", "html": "<blockquote…>" }
Videos for a Douyin hot topic. Query: word (use a hot-search word), offset, count.
curl -s "$BASE/api/douyin/topic-videos?word=%E7%83%AD%E9%97%A8&count=12"
Deep live-room info with FLV / HLS / RTMP pull URLs, viewer count and cover.
{ "room_id": "...", "is_live": true, "viewers": 1617, "streams": { "flv": {...}, "hls": "...m3u8", "rtmp": "rtmp://..." } }
These derived values are computed from a video's stats (and its
duration), and the comment sentiment from the text returned by
/api/video/comments. They appear in the analytics payload and
are useful for comparing videos of different sizes.
| Metric | Formula | Meaning | Range |
|---|---|---|---|
engagement_rate |
(likes + comments + shares) / plays |
Share of views that produced an interaction. | 0–1+ (typ. 0.01–0.20) |
save_rate |
collects / plays |
How often a view leads to a bookmark — intent to revisit. | 0–1 |
share_rate |
shares / plays |
How often a view leads to a share — viral pull. | 0–1 |
comment_rate |
comments / plays |
Conversation intensity per view. | 0–1 |
like_per_1k |
(likes / plays) × 1000 |
Likes per 1,000 views — size-independent comparison. | 0–1000 |
amplification |
(shares + collects) / likes |
Extra distribution per like — how much the audience spreads and saves it. | 0–∞ (typ. 0.01–0.2) |
est_watch_proxy |
engagement_rate × duration |
Engagement rate scaled by video length (seconds) — a relative watch-time signal. | seconds (relative; null without duration) |
sentiment |
lexicon polarity over comment text | Tone of the comment section; returns a label and a score. |
score −1 to 1 |
null — never an invented number — while a missing
numerator counts as zero. Rounded to 4 decimals.
600s, followers 300s, video/reflow 1800s, comments 600s, feed/sound/trending/discover 600s, suggestions 3600s.4 concurrent requests, with a random 0.8–2.0s delay between calls. Exports page at 50 rows per request and sleep 1s between pages.count from 1 to 50 (default 20). Exports accept limit up to 5000 (default 500).400; an upstream scrape failure returns 502 with {"detail": "…"}. Empty upstream payloads usually mean throttling — back off and retry.
Comments
One page of top-level comments on a video, newest first, with cursor paging.
Query:
urlorid,cursor(int, default 0),count(1–50, default 20).Stream all comments for a video as CSV, paging upstream until the limit is reached.
Query:
urlorid,limit(1–5000, default 500).Replies to a specific comment, in the same shape as the top-level comment list.
Query:
item_id(video id),comment_id,cursor,count(1–50).Fetch the top comments on a video and batch-translate them. Each comment gains a
text_translatedfield; the originaltextis preserved.Query:
urlorid(+ optionalauthor),target(language code, defaulten),limit(1–40, default 20).