TikTok

How to scrape TikTok with an API (2026)

Pull TikTok profiles, videos, and search as JSON via Social Fetch — plus DIY browser scraping and TikTok official API limits.

Social FetchUpdated

TikTok scraper jobs — public profiles, videos, comments, search — usually want JSON without standing up Playwright against tiktok.com. This guide covers /v1/tiktok/**, plus what DIY browser scraping and TikTok's official APIs involve on this platform. Generic build-vs-buy: Social Fetch vs DIY scraping. Product hub: TikTok scraper API.

The shortest path is a single request:

Request
curl -sS \
  -H "x-api-key: $SOCIALFETCH_API_KEY" \
  "https://api.socialfetch.dev/v1/tiktok/profiles/charlidamelio"

You'll need an API key and curl or the TypeScript SDK. New to the API? Start with the Quickstart.

DIY browser scraping on TikTok

A plain fetch() to tiktok.com gets blocked almost immediately — TikTok's WAF inspects your TLS fingerprint (JA3/JA4) and a stock HTTP client doesn't match a real browser. Profile data isn't in the DOM; it lives in a __UNIVERSAL_DATA_FOR_REHYDRATION__ blob you have to locate and parse.

Example
python
from playwright.async_api import async_playwright
import asyncio, random

async def scrape_profile(username: str):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False,  # headed sessions trip fewer detection flags
            proxy={
                "server": "http://residential-proxy.example:9000",
                "username": "user",
                "password": "pass",
            },
        )
        context = await browser.new_context(
            user_agent=pick_real_user_agent(),  # from a pool of 50+ current strings
            locale="en-US",
            timezone_id="America/New_York",  # must match the proxy's region
        )
        page = await context.new_page()

        # Warm up: behave like a human before hitting the target
        await page.goto("https://www.tiktok.com/", wait_until="networkidle")
        await asyncio.sleep(random.uniform(3.0, 7.0))

        await page.goto(f"https://www.tiktok.com/@{username}", wait_until="networkidle")
        for _ in range(random.randint(2, 5)):
            await page.mouse.wheel(0, random.randint(600, 1200))
            await asyncio.sleep(random.uniform(1.2, 3.5))

        html = await page.content()
        # The data lives in a JSON blob, not the DOM:
        # parse __UNIVERSAL_DATA_FOR_REHYDRATION__ out of the HTML
        await browser.close()
        return html

A working DIY pipeline also needs:

  • Residential or mobile proxies. Datacenter IPs are flagged within a few hits.
  • Fingerprint patching. Headless Chrome has tell-tale canvas and WebGL signatures — Chrome updates can break your spoofed profile overnight.
  • Token plumbing. The hybrid approach (bootstrap cookies, then replay TikTok's internal JSON endpoints) means babysitting an msToken that expires every few minutes. Every 403 sends you back to launch a browser.
  • Behavioral pacing. Fixed intervals read as a bot, so you add randomized delays and cap concurrency.

TikTok quietly renames internal endpoints and moves fields between JSON blobs. A scraper that worked Tuesday can return empty arrays Friday.

Screenshot of a DIY scrape getting blocked — TikTok's bot-check / CAPTCHA wall, or a browser DevTools Network tab showing a 403 response when hitting a profile from a datacenter IP. Outline the blocked request and the failed/expired msToken in red, with an arrow pointing to the error.
Datacenter IPs hit bot-check walls and tokens expire — the request fails until you rebuild the workaround.

TikTok official APIs

TikTok's developer platform fits apps inside TikTok's ecosystem — user login, publishing, ads, or approved academic research. None of these are a general "look up this public profile" tool:

  • Display API / Embed SDK renders videos and profiles on your site with TikTok's branding — not bulk metadata, comments, or search.
  • Research API exposes more (content metadata, public account data, sometimes comments) but is restricted to academic and non-profit researchers, takes weeks to approve, and prohibits commercial use.
  • Marketing / Commercial APIs cover ads and business accounts, not arbitrary public creator lookups.

Check TikTok for Developers before building against any of them — terms change often.

Using the Social Fetch API

Social Fetch exposes TikTok under documented /v1/tiktok/** routes — profiles, videos, search, comments, transcripts, shop products, and more. One header authenticates every call; responses share the same data + meta envelope across platforms.

Request
TypeScript
const = await client.tiktok.({
handle: "charlidamelio",
});
if (result.ok) {
const { profile } = result.value.data;
}
Response
JSON
{
"data": {
"lookupStatus": ,
"profile": {
"handle": "charlidamelio",
"displayName": "Charli D'Amelio",
},
"metrics": {
"followers": 155200000
}
},
"meta": {
"creditsCharged":
}
}

Hover underlined tokens for details.

Screenshot of the Social Fetch Playground running a TikTok profile lookup: the profile endpoint and a handle entered on the left, the normalized JSON response on the right. Outline the handle, follower metrics, and lookupStatus fields, and add a numbered 1–2–3 callout tracing endpoint → handle → response.
Pick the TikTok profile endpoint, enter a handle, get normalized JSON back.

Get a profile

The same lookup in cURL, the TypeScript SDK, Python, and more — switch tabs to match your stack:

Request
const response = await fetch(
  "https://api.socialfetch.dev/v1/tiktok/profiles/charlidamelio",
  {
    headers: {
      "x-api-key": process.env.SOCIALFETCH_API_KEY,
    },
  }
);

const body = await response.json();

console.log(response.status, body);

List a profile's videos

Request
const response = await fetch(
  "https://api.socialfetch.dev/v1/tiktok/profiles/charlidamelio/videos",
  {
    headers: {
      "x-api-key": process.env.SOCIALFETCH_API_KEY,
    },
  }
);

const body = await response.json();

console.log(response.status, body);

Full parameters: Get TikTok profile and Profile videos. Every TikTok operation is in the API reference.

Paginate through everything

Video and comment endpoints return one page plus a cursor. Pass the cursor back verbatim until it's gone:

Example
typescript
import { SocialFetchClient } from "@socialfetch/sdk";

const client = new SocialFetchClient({
  apiKey: process.env.SOCIALFETCH_API_KEY!,
});

const allVideos = [];
let cursor: string | undefined;

do {
  const result = await client.tiktok.getProfileVideos({
    handle: "charlidamelio",
    cursor,
  });

  if (!result.ok) {
    console.error(result.error.code, result.error.requestId);
    break;
  }

  allVideos.push(...result.value.data.videos);
  cursor = result.value.data.page.nextCursor ?? undefined;
} while (cursor);

Stop when data.page.nextCursor is null. Don't loop on a total count — upstream totals are estimates. The cursor is the source of truth.

Reading the response

A successful response wraps the payload alongside billing metadata:

Response
json
{
  "data": {
    "lookupStatus": "found",
    "profile": {
      "handle": "charlidamelio",
      "displayName": "Charli D'Amelio",
      "verified": true
    },
    "metrics": {
      "followers": 155000000,
      "following": 1200,
      "likes": 11800000000,
      "videos": 2800
    }
  },
  "meta": {
    "requestId": "req_01example",
    "creditsCharged": 1,
    "version": "v1"
  }
}

The one gotcha: an HTTP 200 does not guarantee lookupStatus: "found". A private or non-existent account can return 200 with a status field — handle it in application logic. Every response carries meta.requestId for support tracing. See Errors.

What you can build

  • Influencer vetting — pull profile metrics and recent videos before outreach, and reconcile CRM handles against live numbers.
  • Trend monitoring — combine TikTok search with hashtag endpoints to surface emerging topics on a schedule.
  • Competitive intelligence — snapshot competitor profiles and video performance weekly across every brand you track.
Screenshot of a real dashboard built from the API JSON — a creator profile card with avatar and follower/likes tiles next to a table of recent videos. Draw arrows mapping individual response fields (followers, likes, the video list) to the UI elements they populate.
Profile and videos endpoints mapped onto a vetting or competitive dashboard.

FAQ

It depends on your jurisdiction, what data you collect, and how you use it. Collecting public, business-level metrics for B2B analytics is a common pattern, and courts (e.g. hiQ v. LinkedIn) have generally treated public-web data as fair game in several jurisdictions. You remain responsible for TikTok's terms, applicable privacy law, and your own contracts. This is a technical guide, not legal advice — talk to counsel if you're collecting at scale.

Can't I just use TikTok's official API?

Not for public profile and video lookups. The Research API exposes more data but is academic/non-profit only and bars commercial use; the Display and Commercial APIs handle embedding, login, publishing, and ads. For web-parity public data in a generic backend, a data API is the usual fit. See TikTok official APIs.

How fresh is the data?

Each request fetches live from TikTok at call time — there's no cache returning an hour-old snapshot. If a number looks off, meta.requestId lets support trace that specific lookup.

What happens if a profile is private or doesn't exist?

Check data.lookupStatus. Don't treat a 200 alone as "data is present" — a private or missing account returns 200 with a status field. Details in Errors.

How does this compare to other providers?

See the side-by-side comparisons: vs Apify, vs Bright Data, vs EnsembleData, and the full compare hub.


Next steps: Quickstart · TikTok API reference · Get a video transcript · Pricing

Share this article