TwoSec

Available on RapidAPI

TikTok Video & Creator API

Unofficial API for public TikTok data. Search videos and accounts by keyword, get creator profiles and their posts, read a video's comments and replies, list videos for a hashtag or a sound, and page through follower and following lists. Every endpoint is a GET request that returns JSON, with the same field names everywhere.

Why not TikTok's own API

TikTok's official APIs serve other jobs. Login Kit and the Display API read the account of a user who logs in to your app. The Content Posting API publishes to it. The Research API is limited to academic and not-for-profit researchers, with no commercial use. None of them lets a company search public videos or read any creator's posts and comments.

This API reads the same public pages a logged-out visitor sees. No TikTok account, login or cookies of yours are needed.

Quick start

Subscribe on RapidAPI to get a key; the free plan has 100 requests for testing. Send requests to https://tiktok-video-creator-api.p.rapidapi.com with both headers. This searches videos for "street food":

curl

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'

Python

import os
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",
}

response = requests.get(f"{BASE}/v1/tiktok/search/videos",
                        headers=HEADERS, params={"q": "street food"}, timeout=30)
response.raise_for_status()
for video in response.json()["videos"]:
    print(video["stats"]["plays"], video["url"])

Endpoints

Every call costs one request, whatever the endpoint and however many items the page holds.

PathReturnsPer page
/v1/tiktok/search/videos?q=Videos for a keywordup to 20
/v1/tiktok/search/users?q=Accounts for a keywordup to 10
/v1/tiktok/users/{username}A creator's public profile with exact counts1
/v1/tiktok/users/{username}/videosA creator's posts, newest first (guide)about 30
/v1/tiktok/users/{username}/followersAn account's followers (guide)up to 30
/v1/tiktok/users/{username}/followingThe accounts it followsup to 30
/v1/tiktok/videos/{id}One video or photo post, by ID or URL1
/v1/tiktok/videos/{id}/commentsTop-level comments (guide)usually 33–42
/v1/tiktok/videos/{id}/comments/{comment_id}/repliesReplies to one commentvaries
/v1/tiktok/hashtags/{name}Hashtag info: video and view counts1
/v1/tiktok/hashtags/{name}/videosVideos using a hashtag (guide)about 30
/v1/tiktok/sounds/{id}Sound info and how many posts use it1
/v1/tiktok/sounds/{id}/videosPosts that use a soundabout 30

The full parameter reference is on the RapidAPI listing.

Example response

Real response for GET /v1/tiktok/users/zachking, avatar link shortened

{
  "id": "68616495085350913",
  "username": "zachking",
  "nickname": "Zach King",
  "avatar": "https://p19-common-sign.tiktokcdn-us.com/…",
  "verified": true,
  "sec_uid": "MS4wLjABAAAANnzJ9pdfxtlf3m5Ku_M-rCXVitJC13w4GavqyUD3RE8h1cZ-7O9FT-uQ9rCJjU_E",
  "url": "https://www.tiktok.com/@zachking",
  "bio": "Bringing a little more wonder into the world, 15 seconds at a time",
  "bio_link": "https://youtu.be/ulVscDewRPI?si=-65KnrnwSiGHDeT2",
  "private": false,
  "language": "en",
  "created_at": "2016-02-29T07:29:22Z",
  "stats": { "followers": 86890382, "following": 182, "likes": 1301093987, "videos": 617, "friends": 119 }
}

A video has the same fields wherever it comes from (search, a creator's posts, a hashtag, a sound): id, url, description, created_at, duration, hashtags, stats (plays, likes, comments, shares, bookmarks), author and music. The guides show full video examples.

Pagination

Every list has count, has_more and next_cursor. Pass next_cursor back unchanged as cursor for the next page; it is null on the last page.

def pages(path, **params):
    while True:
        r = requests.get(BASE + path, headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()
        yield data
        if not data.get("has_more") or not data.get("next_cursor"):
            return
        params["cursor"] = data["next_cursor"]

Field notes

Errors

StatusWhen
400Missing or invalid parameter; the body says which
403The account is private
404No such account, video, hashtag or sound (or it was removed)
429Your plan's rate limit
502TikTok failed after our retries; retry with backoff
503Temporarily no capacity; wait for Retry-After

Errors are JSON: {"error": "…"}.

Guides

Without code

For one-off exports without writing code, the same kinds of data are available as Actors on Apify. You run them from the browser and download the results as CSV, Excel or JSON:

Plans and support

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; the same button takes questions and bug reports.