Read a TikTok profile as JSON

Followers, bio and verification for a public account, then the latest videos.

A TikTok profile scraper, in the sense developers search for it, is a way to read the public counts and the bio without driving a browser. The call is GET /v1/tiktok/profile. It returns the name, bio, bio link, verification and exact counts for a public account.

The endpoint is in beta. Send the key in the x-api-key header. Creation and revocation of keys are covered in authentication.

What you send#

Send handle or id. handle is the username, with or without @. username is an alias. id is the numeric TikTok user id. Aliases are user_id, secUid and sec_uid. The reference is explicit: a secUid cannot be looked up logged out. Use the handle or the numeric id.

The recorded request uses a handle.

curl
curl -G "https://api.socialscrape.io/v1/tiktok/profile" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "handle=khaby.lame"
Python
import os
import requests

params = {
    "handle": "khaby.lame",
}
res = requests.get(
    "https://api.socialscrape.io/v1/tiktok/profile",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/tiktok/profile");
url.search = new URLSearchParams({
  "handle": "khaby.lame"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

Check ok before reading data. On failure, branch on error.code and error.retryable, not on the message text. invalid_params and not_found are not retryable. rate_limited is.

max_age_days from 0 to 30 serves a cached copy for 0 credits. This endpoint keeps results 30 days. trim drops nulls and extra. raw adds the platform object. See caching.

What the profile contains#

data is one profile, not a list. object is profile and platform is tiktok.

Identity and text: id, handle, name, headline, url, kind, bio, avatar_url, banner_url. verified and is_private are booleans. external_url and links are the bio link. location, category and created_at are present on the model and null when TikTok does not show them.

stats holds followers, following, posts, likes and views. On a TikTok profile the follower, following, post and like counts are the public totals. views is null when the profile does not carry a view total.

extra on the recorded profile includes comment_setting, download_setting, duet_setting, stitch_setting, following_visible, friends, is_commerce_user, is_organization, is_tiktok_seller, language and sec_uid. Those are platform details, not a second copy of the counts. A field TikTok omits is null.

Sample. The recorded call is handle=khaby.lame, and the sample envelope is shortened. Numbers in that file are the recording, not a live reading. Your own credits_remaining is the live envelope, not the number printed in the sample.

There is no list of followers. stats.followers is a count. If a search result sent you a handle, this is the call that turns it into counts. User search is GET /v1/tiktok/search/users.

The latest videos#

GET /v1/tiktok/profile/videos returns the newest videos of a public account, read from TikTok's embed page, with no login. One page is about 10 videos: pinned videos first, then newest first. Pass handle. The reference says a numeric id cannot be looked up on this route, and sort=popular is refused. include_pinned set to false drops pinned videos that can be told from the page order.

curl
curl -G "https://api.socialscrape.io/v1/tiktok/profile/videos" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "handle=khaby.lame"
Python
import os
import requests

params = {
    "handle": "khaby.lame",
}
res = requests.get(
    "https://api.socialscrape.io/v1/tiktok/profile/videos",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/tiktok/profile/videos");
url.search = new URLSearchParams({
  "handle": "khaby.lame"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

data.items are posts. Each one has id, url, text (the caption), hashtags, published_at, media, song, author and stats. The play count is stats.views. TikTok rounds it to two significant digits, and extra.views_rounded says so. The date is taken from the video id: extra.published_at_from_id. is_pinned is true for a pinned video that can be told from the order. The reference says it never over-reports.

has_more is false and there is no cursor. That is because more videos cannot be fetched logged out, not because the account has only ten videos. parent is the account.

Likes, comments, shares and duration are not on the embed page, so stats.likes, stats.comments, stats.shares and duration_seconds stay null. If you need likes on one video, that is a different call, GET /v1/tiktok/video, with the video URL or id. Do not read a null like count as zero.

A private account answers private on the video list. The profile call's errors are invalid_params and not_found.

Cost#

Each successful call is 1 credit: the profile, and the video page if you take it. Failures cost 0. A repeat inside max_age_days costs 0, and both endpoints keep results 30 days.

Signup includes 100 credits, once, with no card. Packs are one-time and the credits do not expire. Monthly plans reset. See pricing and credits.

Limits#

You get the public profile and about ten recent videos. You do not get the follower list, the full archive, or like counts on that video page. Play counts are rounded. sort=popular on the video list is refused. A secUid is not a logged-out lookup.

The team's rate limit still applies. Free credits are 30 requests a minute. The answer when you pass it is 429 rate_limited, with retry-after, and the refused call is free. Details are on rate limits and errors.

The API is in early access. Both endpoints are beta.

Next#

The profile page, with the sample and every parameter, is the TikTok profile API. The walk-through in more languages is how to scrape a TikTok profile, plus Python and JavaScript. Videos are TikTok profile videos and the reference. The group is the TikTok API.

Finding accounts by a niche word, then opening each profile, is creator research.

Questions

Can I look up a profile by secUid?

Pass handle, or the numeric user id as id. A secUid cannot be looked up logged out. user_id, secUid and sec_uid are aliases of id, but the reference says the secUid lookup does not work logged out.

Does the profile include a follower list?

No. stats.followers is a count. The endpoint does not return the accounts that follow this one.

Can I page through every video?

Not from the profile videos endpoint. You get about 10 videos and has_more is false, because more cannot be fetched logged out, not because the account stopped posting.

Why are likes null on the video list?

The list is read from TikTok's embed page. Likes, comments, shares and duration are not on that page, so they stay null. Play count is present and rounded to two significant digits.

Build on social data early.

Developers and agent builders get the first keys.

Get early access