~ / guides / How to Scrape TikTok: Methods & Avoiding Blocks

How to Scrape TikTok: Methods & Avoiding Blocks

AQ
Aria Quinn
TikTok data engineer · about the author
the short version
  • A default Python requests.get to a TikTok profile returned HTTP 403 with an empty body for me. Adding a real browser User-Agent flipped the same call to 200 and 363 KB of HTML in my June 2026 test.
  • The page data lives in a script tag named __UNIVERSAL_DATA_FOR_REHYDRATION__. I parsed it and pulled followerCount, secUid, and videoCount for @tiktok (94.4M followers, verified) straight out of the JSON.
  • Four methods scale differently: the hidden-JSON method, browser automation with Playwright, the official TikTok Research API (academic-only, 1,000 requests/day), and a scraper API that returns parsed JSON.
  • TikTok blocks on IP reputation, TLS fingerprint, and request signatures (X-Bogus, msToken). Past a few thousand records, rotating that yourself costs more time than it saves.

I tried to scrape TikTok the lazy way first: one requests.get against https://www.tiktok.com/@tiktok with Python’s default settings. It came back 403 with an empty body before I had parsed anything. Then I changed one header, a real browser User-Agent, and the same URL returned 200 and 363 KB of HTML with every field I wanted sitting inside it.

This guide is the TikTok data scraping methods I actually ran in June 2026, in order of how far each one scales: the hidden-JSON method, browser automation, the official Research API, and a scraper API. I will show you the code that returned data, the exact JSON keys it came back in, and how to scrape TikTok without getting blocked once you move past a handful of requests.

What is the fastest way to scrape TikTok data?

The fastest way to scrape TikTok data is to read the JSON that TikTok already embeds in every public page. You do not need to call a hidden endpoint at all for the first batch. When you request a profile, video, or hashtag URL with a browser User-Agent, TikTok returns the rendered HTML with a script tag named __UNIVERSAL_DATA_FOR_REHYDRATION__. The browser uses that JSON to hydrate the page, and a scraper can parse the same JSON directly.

Install the one dependency and run the request below. The only thing that matters at this stage is the User-Agent.

pip install requests
import requests, re, json

UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
      "(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36")

url = "https://www.tiktok.com/@tiktok"
r = requests.get(url, headers={"User-Agent": UA}, timeout=25)
print(r.status_code, len(r.text))   # -> 200 362971

m = re.search(
    r'<script id="__UNIVERSAL_DATA_FOR_REHYDRATION__"[^>]*>(.*?)</script>',
    r.text, re.S,
)
data = json.loads(m.group(1))
user_info = data["__DEFAULT_SCOPE__"]["webapp.user-detail"]["userInfo"]

print(user_info["user"]["nickname"], user_info["user"]["verified"])
print(user_info["stats"]["followerCount"], "followers")
print(user_info["stats"]["videoCount"], "videos")
print(user_info["user"]["secUid"][:18], "...")

This is the real output from my run against @tiktok:

200 362971
TikTok True
94400000 followers
1450 videos
MS4wLjABAAAAv7iSuu ...

The profile data lives under the webapp.user-detail key, inside userInfo. From there user holds the identity fields (nickname, verified, secUid, and the numeric userId) and stats holds the counts (followerCount, videoCount, heartCount). The secUid is the value you reuse later to page through a creator’s videos, so grab it on the first request and cache it.

One field caught me out. When I ran the same code against @khaby.lame (162M followers) in June 2026, the heartCount came back as -1667674838, a negative number, and @charlidamelio did the same. That is a 32-bit signed integer overflow in TikTok’s own payload once total likes pass roughly 2.1 billion. If you store likes as a 32-bit int you inherit the bug, so read high-volume creator stats as 64-bit. That kind of edge case only shows up when you scrape live data instead of reading a tutorial.

The hidden-JSON method is enough for profiles, single videos, and hashtag landing pages. The wall you hit next is the feed: lists of videos, comments, and search results load from internal API calls after the page renders, and those calls are signed. That signature is the subject of the next sections.

How do you scrape TikTok videos and user data at scale?

You scrape TikTok videos and a creator’s full user data by paging through the internal item-list endpoint, using the secUid you pulled from the profile JSON. The first page of videos ships inside __UNIVERSAL_DATA_FOR_REHYDRATION__, but everything past the initial batch comes from https://www.tiktok.com/api/post/item_list/, which returns video objects plus a cursor for the next page.

The response shape is what makes pagination work. Each call returns three fields that drive the loop:

FieldTypeWhat it does
itemListarrayThe batch of video objects (id, desc, stats, video, author)
hasMorebooleantrue if more videos exist past this page
cursorstringThe offset value you pass to fetch the next page

The loop is simple in principle: read itemList, check hasMore, and if it is true, send the cursor value back as the cursor query parameter on the next request. You repeat until hasMore is false.

# Pagination contract for scraping TikTok videos (the signing step is omitted).
# Two variables drive the loop: a cursor value and the hasMore flag.
def scrape_tiktok_videos(sec_uid):
    cursor_value = "0"
    videos = []
    while True:
        resp = call_item_list(sec_uid=sec_uid, cursor=cursor_value)  # needs a signature
        videos.extend(resp["itemList"])      # each item holds a tiktokcdn.com video URL
        if not resp["hasMore"]:              # hasMore == False ends the loop
            break
        cursor_value = resp["cursor"]        # carry the cursor into the next call
    return videos

Two variables drive that function: cursor_value, which you carry forward on every call, and the hasMore flag, which tells you when to stop. Each item in the tiktokList of results also carries the download address on TikTok’s CDN (tiktokcdn.com) under video.playAddr, so walking the full result set gives you both the metadata and the media links in one pass.

The catch is call_item_list. I sent a raw, unsigned GET to /api/post/item_list/ in my June 2026 test and it returned HTTP 200 with a body of exactly zero bytes: no error, no JSON, just an empty response. TikTok rejects that request unless the URL carries a valid X-Bogus signature and an msToken, both generated by a virtual machine TikTok runs in the browser, and Scrapfly’s 2026 teardown and the tiktok-web-reverse-engineering project both document how that signature is derived from the signed URL combined with the msToken and User-Agent. Reproducing it in Python means running TikTok’s signer in a JS runtime or driving a real browser, which is why browser automation exists as method two and a signing API exists as method four.

The same itemList plus hasMore plus cursor contract drives the other TikTok surfaces too, which the next section covers.

How do you scrape TikTok hashtag pages, search, and location content?

You scrape TikTok hashtag pages, user search results, and location-tagged content with the same cursor loop as the video list, pointed at a different endpoint. Once you have written one paginated scraper, these surfaces are the same code with a new path and a different id field. Each one returns an itemList, a hasMore flag, and a cursor, and each internal endpoint is signed exactly like item_list.

TikTok surfaceEndpointKey inputPagination
Hashtag pages/api/challenge/item_list/challengeIDcursor + hasMore
User search results/api/search/general/full/keywordoffset + hasMore
Location-tagged content/api/poi/item_list/ (place id)poiIdcursor + hasMore
Live streaming dataWebSocket gift/chat streamroom idstreamed events

Hashtag and location endpoints carry the first page inside the rehydrated page JSON, so the landing page gives you a starting batch the same way a profile page does. You only need signed calls once you page past it. Search is the exception that surfaces in TikTok’s robots.txt: the file sets Disallow: /search?, /search/video?, and /search/user?q= for the catch-all User-agent: *, so search result pages are explicitly fenced off from crawlers even though the endpoint exists.

Live streaming data does not follow the cursor pattern at all. To scrape data from a TikTok LIVE room you connect to a WebSocket that streams gift and chat events in real time. Paging a static list does not apply here. It is a separate build from the rest of this guide, and the open-source tiktok-live-connector project is the usual starting point for that one specifically.

With the read surfaces mapped, comments are the one most projects ask about next, and they have their own quirk.

How do you scrape TikTok comments?

You scrape TikTok comments from the internal endpoint https://www.tiktok.com/api/comment/list/, which takes a video’s aweme_id and returns comment objects with the same hasMore and cursor pagination contract as the video list. The aweme_id is the long numeric id in a video URL (/video/7300000000000000000), and it is also present in each item object from the post list.

The comment payload gives you the fields most projects want:

FieldDescription
comments[].textThe comment body
comments[].digg_countLikes on the comment
comments[].user.unique_idCommenter’s @handle
comments[].reply_comment_totalNumber of replies
cursor / hasMorePagination, same contract as the video list

The blocker is identical to the video list: /api/comment/list/ is a signed endpoint. Without a valid X-Bogus and msToken the request returns the same empty body I measured on item_list, so a raw requests call will not return the comment JSON the way the profile page does. This is why comment scraping is the method people most often hand off. If you need replies as well as top-level comments, you page a second endpoint (/api/comment/list/reply/) once per comment, which multiplies the signed request count fast.

For volume comment collection, I point people at a purpose-built TikTok comment scraper API that signs each request and walks the cursor for you, so you send a video URL and get the full comment tree back as JSON. For a handful of videos, automating a real browser avoids the signing problem entirely, which is the next method.

How do you avoid getting blocked when scraping TikTok?

You avoid getting blocked on TikTok by fixing three signals in this order: the User-Agent, the IP reputation, and the request rate. The signature requirement is a separate problem, but blocking is what stops most scrapers first, and the User-Agent is the cheapest signal to fix.

My single most useful test was the User-Agent. The two requests below differ by one header and nothing else:

RequestUser-AgentStatusBody
GET /@tiktokPython default (python-requests/2.x)4030 bytes
GET /@tiktokChrome 126 desktop string200362,971 bytes

A blank 403 is the signature of a missing or non-browser User-Agent. Fixing that one header is the difference between zero bytes and the full page. After that, the levers that moved results in my testing, in rough order of impact:

The honest tradeoff: doing all of this yourself means buying a residential proxy pool, rotating it, faking realistic headers, refreshing tokens, and generating the X-Bogus signature for every internal call. That becomes a standing maintenance project once you pass a few thousand records, which is why most teams move the blocking and signing problem to a TikTok scraper API. Browser automation sidesteps the signature entirely, which is the next decision to weigh.

Should you use browser automation or the official API?

Use browser automation when you need signed data (video lists, comments, search) without reverse-engineering the signature, and use the official Research API only if you qualify as an academic researcher. They solve different problems, so the right choice depends on what data you need and who you are.

Browser automation with Playwright drives a real Chromium instance, so TikTok generates the X-Bogus signature and msToken for you as the page runs. You let the page load, scroll to trigger the feed requests, and read the responses or the rehydrated state. The cost is resources: a real browser per worker is far heavier than an HTTP request, and you still need residential proxies to clear the IP blocks above. It is the most reliable self-hosted method, and the slowest. The open-source TikTok-Api library by David Teather wraps this approach (MIT licensed, v7.x as of mid-2026), driving Playwright so the page signs your calls.

The official TikTok Research API is the clean, sanctioned route, but access is narrow. Per TikTok’s Research API FAQ, the standard quota is 1,000 requests per day for up to 100,000 records, video and comment endpoints return 100 records per request, and the quota resets at 12 AM UTC, while the follower and following endpoints get a higher ceiling of 20,000 calls per day for up to 2 million records. Eligibility is the real gate: TikTok’s Research Tools terms limit access to approved academic institutions in the US, EEA, UK, and Switzerland, not-for-profit research bodies in the EU, and qualifying Brazilian institutions focused on youth safety, and a developer account alone does not grant access. A 2026 evaluation in the Social Science Computer Review found measurable demographic sampling bias in what the Research API returns, so even approved researchers validate it against other data.

Here is how the four methods compare on the dimensions that decide which one you pick:

MethodAuthSigned requestsScales toBest for
Hidden-JSON (__UNIVERSAL_DATA_FOR_REHYDRATION__)None (browser UA)First page onlyProfiles, single videos, hashtag pagesQuick public-page pulls
Browser automation (Playwright)NoneHandled by the browserFeeds, comments, search (slowly)Signed data without reversing X-Bogus
Official Research APIApproved credentialsN/A (sanctioned)100k records/dayAcademic and non-profit research
Scraper API (ChocoData)API keyHandled server-sideContinuous, high volumeProduction pipelines, no proxy or signing work

A commercial team that just needs the data and does not qualify for the Research API fits neither raw scraping nor the academic route cleanly. That gap is what the scraper-API method fills.

How do you scrape TikTok without managing proxies or signatures?

You scrape TikTok without managing proxies or signatures by sending a TikTok URL to a scraper API and getting parsed JSON back, with the IP rotation, browser fingerprint, and X-Bogus signing handled on the server side. You send one request with your API key. You get structured data. There is no 403 to debug and no signer to maintain.

With ChocoData, a profile pull is a single call. The TikTok endpoints live under the tiktok path, and you pass your key as api_key:

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

The same pattern covers the other object types by swapping the path: a TikTok profile scraper endpoint for user data, a video scraper endpoint that walks the cursor loop for a creator’s catalog, and a hashtag scraper endpoint for trending tags, none of which need you to touch secUid, aweme_id, or a signature. In Python it is the same one request:

import requests, os

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

This returns the same fields the hidden-JSON method exposes (followerCount, videoCount, secUid, userId), without registering an app, running Playwright, rotating proxies, or installing a JS signer in your environment. For a one-off pull of a few public profiles, the hidden-JSON code at the top of this guide is genuinely all you need. For continuous collection across many creators, hashtags, and comment threads, offloading the blocking and signing is the cheaper path once you price in your own time. If you are weighing a managed actor against a direct API, I compare the tradeoffs in my TikTok scraper alternatives breakdown, and I rank the managed options head to head in best TikTok scrapers in 2026.

Before you collect anything at volume, it is worth knowing where the legal line sits. US courts have repeatedly protected scraping of public, logged-out data: the Ninth Circuit in hiQ v. LinkedIn held that the CFAA does not bar access to public pages, and in Meta v. Bright Data (N.D. Cal., January 2024) Judge Edward Chen found Meta’s terms do not prohibit logged-off scraping of public data. That said, TikTok’s robots.txt sets Disallow: / for a long list of named bots and allows only a specific path list for everyone else, and logged-in or private data is a separate question. I cover the full picture, including TikTok’s Terms of Service, in is scraping TikTok legal, and the Python-specific build in how to scrape TikTok with Python.

FAQ

Can you scrape TikTok without an API key?

Yes, for public profile, video, and hashtag pages. TikTok embeds the page data in a __UNIVERSAL_DATA_FOR_REHYDRATION__ script tag that you can parse from the raw HTML with a real browser User-Agent. The limits are IP-based blocking and request signing on the internal feed endpoints, which is where most no-key scrapers stall at scale.

Why does my TikTok scraper return 403 or an empty page?

A blank 403 almost always means a missing or non-browser User-Agent, or a datacenter IP that TikTok has flagged. In my June 2026 test a default Python User-Agent returned HTTP 403 with zero bytes. The same request with a Chrome User-Agent returned 200 and the full 363 KB page. Beyond the profile HTML, the internal API endpoints also require a valid signature (X-Bogus) and an msToken.

How do you scrape TikTok comments?

Comments come from the internal endpoint /api/comment/list/, which needs the video aweme_id plus a signed request and a cursor value for pagination. It returns a hasMore flag and a cursor for the next page. Because the signature is the hard part, most people pull comments through a TikTok comment scraper API that signs requests server-side.

Does the TikTok Research API let anyone scrape data?

No. The TikTok Research API is restricted to approved academic and non-profit researchers in the US, EEA, UK, Switzerland, and qualifying Brazilian institutions. A developer account alone does not grant access. You submit a research proposal, pass an ethics review, and the standard quota is 1,000 requests per day.

How much TikTok data can the Research API return per day?

TikTok's documentation sets the standard quota at 1,000 requests per day for up to 100,000 records, with video and comment endpoints returning 100 records per request. The follower and following endpoints allow up to 20,000 calls per day for up to 2 million records. The quota resets at 12 AM UTC.

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.