~ / guides / How to Scrape TikTok With Python

How to Scrape TikTok With Python

AQ
Aria Quinn
TikTok data engineer · about the author
the short version
  • TikTok server-renders page data into a <script id="__UNIVERSAL_DATA_FOR_REHYDRATION__"> tag. A single Python requests call to a profile URL returned HTTP 200 with that JSON intact for me in June 2026.
  • Parsing that JSON gives you uniqueId, secUid, userId, follower stats and the video list. The secUid is the key you need to page through videos with cursor and hasMore.
  • The list and comment endpoints need a signed request (X-Bogus / msToken) plus a residential IP. Datacenter IPs get blocked fast, which is where a raw script stops scaling.
  • For volume, a scraper API takes a username and returns parsed JSON with the signing and proxies handled server side. Same data, no signature to reverse-engineer.

I learned how to scrape TikTok with Python the laziest possible way: one requests.get against tiktok.com/@nasa, no browser, no proxy. It came back 200 with a 363 KB HTML page, and buried in that page was a script tag holding the entire profile as JSON. That is the whole trick to scraping TikTok with Python, and most of this guide is about that one tag, how far it gets you, and where it stops.

Below is the exact code I ran in June 2026, what TikTok actually returned, and the point where a raw script gives way to a signed request or an API. If you came here searching for a tiktok scraper python recipe, the first script is the whole starting point, and the later sections explain why it stops scaling.

How do you scrape TikTok with Python?

You scrape TikTok with Python by fetching a public page and parsing the JSON that TikTok server-renders into it. Every profile and video page ships with a <script id="__UNIVERSAL_DATA_FOR_REHYDRATION__"> tag, and that tag contains the structured data the page uses to render: the username, the secUid, follower counts, and the first batch of videos. You do not need to drive a browser to read it.

Here is the minimal scraper I ran. It uses requests to fetch the page and a regex plus json.loads to pull the embedded data. Install the one dependency first:

pip install requests
import requests, re, json

URL = "https://www.tiktok.com/@nasa"
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
      "(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36")

resp = requests.get(URL, headers={"User-Agent": UA}, timeout=25)
print(resp.status_code)                  # -> 200

# TikTok embeds page state in this script tag
match = re.search(
    r'<script id="__UNIVERSAL_DATA_FOR_REHYDRATION__"[^>]*>(.*?)</script>',
    resp.text, re.S,
)
data = json.loads(match.group(1))
scope = data["__DEFAULT_SCOPE__"]
user_info = scope["webapp.user-detail"]["userInfo"]

user = user_info["user"]
stats = user_info["stats"]
print(user["uniqueId"])        # nasa
print(user["secUid"][:24])     # MS4wLjABAAAAGucQjvCZ86kq...
print(user["id"])              # the numeric userId
print(stats["followerCount"])  # follower count
print(stats["videoCount"])     # number of videos

When I ran this, the response was 200 with content-type: text/html, and the __UNIVERSAL_DATA_FOR_REHYDRATION__ tag was present (the older SIGI_STATE tag was not, TikTok has moved on from it). Parsing it gave me the uniqueId (nasa), the secUid, the numeric userId, and the stats block. The secUid is the value that matters most downstream: it is the opaque user id TikTok wants when you ask for that account’s video list, and you cannot guess it, you have to read it off the profile first.

One honest caveat from my own run: the followerCount and videoCount I got back looked like edge or sandbox values, and they drifted between requests, so they did not match the live public totals a browser shows. The JSON structure itself was real and stable; only the specific stat numbers moved. Treat the shape as reliable and verify any count against a second request before you report it. With the profile parsed, the next thing most people want is that account’s videos, which is where the page JSON runs out.

How do you scrape TikTok videos with Python?

You scrape TikTok videos with Python by calling the item-list endpoint with the secUid you pulled from the profile, then paging through results with a cursor. The profile page JSON only carries the first handful of videos. To get the rest, you request https://www.tiktok.com/api/post/item_list/, which returns an itemList array, a numeric cursor for the next page, and a hasMore boolean that tells you when to stop.

The shape of that loop looks like this:

def fetch_videos(sec_uid, signed_url_builder, pages=3):
    cursor_value = "0"
    videos = []
    for _ in range(pages):
        params = {
            "secUid": sec_uid,
            "count": 35,
            "cursor": cursor_value,
        }
        # TikTok rejects this URL unless it is signed (see below)
        url = signed_url_builder("/api/post/item_list/", params)
        data = requests.get(url, timeout=25).json()

        videos.extend(data.get("itemList", []))
        cursor_value = data.get("cursor")     # feed back into next request
        if not data.get("hasMore", False):    # False means last page
            break
    return videos

Each item in the itemList array carries the fields a TikTok video scraper in Python actually needs: the video id (also called aweme_id), the description, the createTime, the stats block with play, like, comment and share counts, the author, and the playable URL on a *.tiktokcdn.com host. The fetch_videos function above keeps two variables in play across the loop: cursor_value, which you read out of each response and feed back into the next request, and the hasMore flag, which flips to false on the final page. Using those two together is the whole pagination contract for this endpoint.

There is a catch that the code above hides behind signed_url_builder. A raw requests.get to /api/post/item_list/ does not work the way the profile fetch did. That endpoint is signed, and that signing is the real wall in front of scaling TikTok scraping.

Why do TikTok’s API endpoints reject a plain request?

TikTok’s internal endpoints reject a plain request because they require a signature that proves the call came through TikTok’s own JavaScript. The profile HTML is open, but the JSON APIs behind it (item_list, comment/list, search) expect an X-Bogus or X-Gnarly parameter plus an msToken, all generated by an obfuscated virtual machine that runs in the browser. Strip those off and TikTok returns an empty body or an error.

This is why the simple requests approach has a ceiling. To call the list endpoints yourself you have to reproduce the signature, and there are two practical ways to do it:

ApproachHow it signsStrengthWeakness
Headless browser (Playwright)Loads TikTok’s real JS, lets the page sign the URLAlways current signing logicHeavy, slow, memory-hungry per request
Signing service / libraryRuns TikTok’s signer VM in Node to mint X-Bogus + msTokenFast, no full browser per callBreaks when TikTok rotates the VM
Scraper APIVendor signs server side for youNothing to maintain locallyPer-request cost

The open-source TikTok-Api library by David Teather takes the first route: it drives Playwright so the page generates the signature, then reuses it for your calls. It is MIT licensed, sits at version 7.x as of mid-2026, and covers users, videos, hashtags and trending. Its own docs are clear that it cannot post content and has no authenticated routes, and the release notes show it gets patched whenever TikTok changes its signing, so pin a version in your environment and budget for upkeep.

Signing is only half the wall. Even a perfectly signed request fails if it comes from the wrong IP.

How do you scrape TikTok without getting blocked?

You avoid TikTok blocks by sending signed requests from residential IPs at a human-like rate, because TikTok blocks datacenter ranges quickly and rate-limits aggressively. The signature gets you past the “is this our JavaScript” check. The IP reputation gets you past the “is this a bot farm” check. You need both.

These are the levers that matter, in rough order of impact:

The honest tradeoff is the same one I hit on every platform. Doing this yourself means renting a residential proxy pool, rotating it, running a signer that you patch every time TikTok ships a change, and retrying failures. That is a standing maintenance project once you pass a few thousand records, and it is the reason most teams hand the signing and proxies to an API. Comments are the clearest example, because that endpoint is signed and paginated in exactly the same way.

How do you scrape TikTok comments with Python?

You scrape TikTok comments with Python by calling the comment-list endpoint with a video’s aweme_id and paging through with a cursor, the same pattern as the video list. The endpoint is https://www.tiktok.com/api/comment/list/, it takes the video id plus a cursor and a count, and it returns a comments array alongside cursor and hasMore for pagination.

The loop is structurally identical to the video scraper, which is the useful part: once you have written one paginated TikTok scraper in Python, comments are the same code with a different path and id field.

def fetch_comments(aweme_id, signed_url_builder, pages=5):
    cursor_value = 0
    out = []
    for _ in range(pages):
        params = {"aweme_id": aweme_id, "count": 20, "cursor": cursor_value}
        url = signed_url_builder("/api/comment/list/", params)
        data = requests.get(url, timeout=25).json()
        for c in data.get("comments", []):
            out.append({
                "text": c["text"],
                "likes": c["digg_count"],
                "user": c["user"]["unique_id"],
            })
        cursor_value = data.get("cursor", 0)
        if not data.get("has_more"):
            break
    return out

Because comment/list is one of the signed endpoints, a bare requests.get against it returns nothing usable. You are back to the signing requirement from the previous section: either a Playwright-driven signer or a service that mints the signature. A Python TikTok comment scraper that skips signing simply does not get comments back.

At this point the pattern is clear. The free part of TikTok scraping is the page JSON. The part that takes real engineering is signing and IP reputation, and that work is identical whether you are after profiles, videos, or comments. That is precisely the part a scraper API absorbs.

How do you scrape TikTok at scale with an API?

A scraper API handles TikTok at scale by taking a username or video id and returning parsed JSON, with the signing, the msToken, and the residential proxies all handled server side. You make one authenticated request and get structured data back, with no signature to reverse-engineer and no proxy pool to rent.

The call is a single GET. You pass the target and your key, shaped like this against the ChocoData API:

curl "https://chocodata.com/api/v1/tiktok/profile?username=nasa&api_key=$CHOCO_API_KEY"

The Python version is just as short, and it returns the same secUid, userId, stats and video fields you would have parsed by hand, already cleaned:

import os, requests

resp = requests.get(
    "https://chocodata.com/api/v1/tiktok/profile",
    params={"username": "nasa", "api_key": os.environ["CHOCO_API_KEY"]},
    timeout=30,
)
profile = resp.json()
print(profile["user"]["secUid"])
print(profile["stats"]["followerCount"])

The trade is straightforward. For a one-off pull of a few profiles, the raw requests script in the first section is genuinely all you need, and it is free. For continuous collection across many accounts, hashtags or comment threads, the signing breaks on TikTok’s schedule and datacenter IPs get blocked, so offloading both is usually cheaper than your own time once you price it in. ChocoData exposes the same surfaces this guide walked through as dedicated endpoints: a profile scraper, a video scraper, and a comment scraper, each keyed on the same secUid and aweme_id values you saw above. You can get an API key and run the profile call above in a couple of minutes.

If you are weighing whether to scrape at all, the legal footing matters as much as the code. US courts have repeatedly protected logged-out scraping of public data: the Ninth Circuit in hiQ Labs v. LinkedIn held that scraping public pages is not unauthorized access under the CFAA, and the Northern District of California in Meta v. Bright Data found that logged-out scraping of public data does not breach a platform’s terms. TikTok’s Terms of Service and any personal data are separate questions, which I work through in is scraping TikTok legal. For the full menu of approaches beyond Python (no-code tools, the official Research API, and managed services), see how to scrape TikTok.

Should you use the official TikTok Research API instead?

The official TikTok Research API is the sanctioned route, but it is gated to non-commercial academic and nonprofit work, so it is not an option for most builders. TikTok grants it to academic institutions in the US, EEA, UK or Switzerland and to not-for-profit research bodies in the EU, and applicants have to submit a research proposal, pass an ethics review, disclose funding, and commit to data-security terms. Approval can take up to four weeks.

Where it fits, it is generous: TikTok’s own product page lists access to public account data (profiles, follower and following lists, liked, pinned and reposted videos), video content, and TikTok Shop data. Where it does not fit is anything commercial. The eligibility terms rule out building a paid tool on top of it, and review timelines and per-query caps make it unsuitable for production pipelines that need data today.

RouteBest forAuthSigning / proxiesCommercial use
Raw requests + page JSONA few public profilesNoneNot needed (profile only)Allowed (public data)
TikTok-Api (Playwright)Small projects, learningNoneYou maintain itAllowed, you carry upkeep
Official Research APIAcademic / nonprofit studiesApproved accountHandled by TikTokNot permitted
Scraper API (ChocoData)Production, at scaleAPI keyHandled server sideAllowed

The decision comes down to volume and purpose. A keyless Python script reads public profile JSON for free and is the right call for a handful of pages. The Research API serves approved academic work. A scraper API covers production collection where signing and proxies would otherwise be a permanent maintenance line. Each one returns the same core fields you saw parsed out of that first __UNIVERSAL_DATA_FOR_REHYDRATION__ tag.

FAQ

Can you scrape TikTok with Python without an API key?

Yes, for public profile and video pages. TikTok embeds the page data in a __UNIVERSAL_DATA_FOR_REHYDRATION__ script tag that a plain requests.get can fetch and json.loads can parse. The limit is volume: the list endpoints need a signed request and a residential IP, so a keyless script works for a handful of pages and stalls past that.

What is the best Python library to scrape TikTok?

The most used open-source option is TikTok-Api by David Teather (MIT licensed, v7.x), which drives Playwright to generate TikTok's request signatures for you. It covers users, videos, hashtags and trending. It cannot post content and has no authenticated routes. It breaks when TikTok rotates its signing, so pin a version and expect maintenance.

How do you scrape TikTok comments with Python?

Comments come from TikTok's /api/comment/list/ endpoint, which takes an aweme_id (the video id) and a cursor, and returns a comments array with hasMore for pagination. That endpoint requires a signed URL, so a raw requests call returns an empty or rejected response. A TikTok comment scraper in Python either uses a signing library or calls a scraper API that signs the request for you.

Is scraping TikTok with Python legal?

Scraping public TikTok pages while logged out sits on the safer side of US case law after hiQ v. LinkedIn and Meta v. Bright Data, which held that logged-out scraping of public data does not breach a site's terms. Logged-in scraping, personal data and TikTok's Terms of Service are separate questions. I cover the detail in the legal guide linked below.

AQ
Aria Quinn
I've built TikTok data pipelines for years. On tiktokscraperapi.com I run TikTok scraping methods against live pages and publish what actually holds up.