How to scrape TikTok at scale in 2026 with proxies that work
TikTok now holds more daily attention than almost any other platform, which means its data, video metadata, hashtag volumes, creator follower counts, comment sentiment, sound usage, is worth pulling if you’re doing market research, competitor tracking, or trend spotting for a brand. The problem is that TikTok does not want you doing this. It fingerprints browsers, rate limits IPs within minutes of unusual traffic, and reshuffles its page structure often enough that a script working in one quarter breaks by the next.
This is for growth marketers, researchers, and agencies who need TikTok data at a volume beyond what you can screenshot by hand, think hundreds to tens of thousands of videos or profiles a day. It’s not for anyone trying to impersonate accounts, pull data from behind a login wall it wasn’t meant to be accessed from, or run a bot network. I’ll walk through the stack I actually use: Playwright for rendering, a rotating proxy pool, and a pipeline that survives TikTok’s blocking without needing a rebuild every few weeks.
By the end you’ll have a working collector that pulls public video and profile data through residential proxies, a sense of where TikTok’s defenses will bite you, and a rough map of what changes as you go from a weekend project to something running continuously across thousands of requests a day. None of this requires TikTok’s official API, which is restricted to approved research and business partners.
what you need
- A residential or mobile proxy plan, not datacenter. TikTok blocks known datacenter ranges almost on sight. Expect to pay somewhere in the $4 to $15 per GB range depending on provider and traffic volume.
- Python 3.10 or newer, plus Playwright (
pip install playwright playwright-stealththenplaywright install chromium). - Somewhere to land the data. A local SQLite file is fine to start, Postgres once you’re running daily.
- One or two TikTok accounts for pages that sit behind a soft login wall, treat them as expendable.
- Time to babysit the first few runs. TikTok’s block patterns shift within the first 48 hours of any new IP range you introduce.
- Optional: a captcha-solving service like 2Captcha or CapSolver for when TikTok serves its slider verification.
step by step
1. Define your scope and pick a legal lane
Decide exactly what data you need, video metadata under a hashtag, profile stats for a fixed list of creators, comment counts, before writing any code. TikTok’s Terms of Service prohibit automated data collection outright, and its robots.txt disallows crawling most paths, so you’re relying on the general principle that scraping publicly viewable web pages has held up in US courts in cases like hiQ v. LinkedIn, not on TikTok’s permission. This is not legal advice, if you’re doing this commercially or outside the US, check with a lawyer first.
Expected output: a written scope, something like “top 200 videos per hashtag for 15 hashtags, refreshed daily.”
If it breaks: scope creep is the real failure mode here. If your target list keeps growing mid-project you’ll burn through proxy bandwidth and hit bans faster than you can diagnose why. Lock the scope before step 2.
2. Choose your proxy type
Rent residential or mobile proxies from a provider with real ISP-assigned IPs. Datacenter ranges from AWS, OVH, or Hetzner get flagged and served verification challenges almost immediately. I’ve had the most consistent results with Decodo for this, see my Decodo review for current pricing and what the rotation options actually look like.
Expected output: a proxy endpoint (host:port) with rotating or sticky session credentials from your provider’s dashboard.
If it breaks: if you’re seeing captcha challenges or empty response bodies within your first ten requests, the IP is already burned. Rotate to a different subnet, not just a new address in the same /24.
3. Set up your scraping stack
Install Playwright. It renders TikTok’s JavaScript-heavy pages the way a real browser does, which matters because most of the content on TikTok’s web app is built client side rather than served in the initial HTML.
python -m venv tiktok-scraper
source tiktok-scraper/bin/activate # .\tiktok-scraper\Scripts\activate on Windows
pip install playwright playwright-stealth
playwright install chromium
Playwright’s official docs are the best reference once you start hitting edge cases, the API changes underneath you more often than you’d expect from a browser automation tool.
Expected output: a chromium binary installed in Playwright’s cache, ready to launch headless.
If it breaks: if playwright install hangs or times out, you’re probably behind a network that’s blocking the binary download. Try a clean connection or set PLAYWRIGHT_DOWNLOAD_HOST to a mirror.
4. Build the collector script
Write a script that launches a browser through your proxy, navigates to a public TikTok page (hashtag, profile, or single video), and waits for content to render before extracting it. A realistic desktop User-Agent header matters more than people assume, a stale or mismatched one is an easy signal for TikTok to flag.
import asyncio
from playwright_stealth import stealth_async
from playwright.async_api import async_playwright
PROXY = {"server": "http://proxy-host:port", "username": "user", "password": "pass"}
async def fetch_hashtag_page(tag: str):
async with async_playwright() as p:
browser = await p.chromium.launch(proxy=PROXY, headless=True)
page = await browser.new_page(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
)
await stealth_async(page)
await page.goto(f"https://www.tiktok.com/tag/{tag}", timeout=30000)
await page.wait_for_timeout(3000)
html = await page.content()
await browser.close()
return html
asyncio.run(fetch_hashtag_page("smallbusiness"))
TikTok’s web app has, at various points, embedded page data as a JSON blob in the HTML itself. Look for a script tag holding something like an app-state object before you go hunting through the rendered DOM for it, it’s more stable across UI changes than CSS selectors are.
Expected output: raw HTML containing video cards for the hashtag page, usually 20 to 30 videos on the first load.
If it breaks: a page that loads but returns no video cards usually means you hit a verification wall instead of the real page. Check page.content() for phrases like “verify to continue” and route that session to a captcha solver or drop it entirely.
5. Handle the verification wall and login-gated content
Some pages, especially search and certain profile views, throw a slider captcha or require a login. Keep a small pool of throwaway TikTok accounts logged in via saved Playwright storage state for pages that need it, and send anything that hits the slider through a solving service rather than trying to automate the drag gesture yourself, TikTok’s slider checks the motion curve of the drag, not just the end position.
Expected output: a storage_state.json file per account so you skip re-login on every run.
If it breaks: if an account’s feed suddenly goes blank or actions silently fail, it’s been soft-banned. Retire it. Continuing to run a flagged account poisons the session for anything else sharing that proxy.
6. Add rotation, throttling, and session management
Pair each browser session with one sticky proxy IP for its lifetime, then rotate to a new IP for the next session. Space requests with randomized delays rather than a fixed interval, a flat, regular cadence is one of the easier bot signals to catch.
import random
async def polite_delay():
await asyncio.sleep(random.uniform(2.5, 6.0))
Expected output: request timing that looks irregular in your logs, not machine-metronomic.
If it breaks: if you’re still getting blocked with rotation and delays in place, check whether your proxy pool is recycling IPs that were burned in an earlier run. Most providers let you exclude recently used addresses from the pool.
7. Parse and store the results
Extract the fields you actually need, video ID, author, likes, shares, comment count, sound ID, and write to storage immediately after each successful fetch. Don’t hold results in memory across a long run.
Expected output: rows landing in SQLite or Postgres as the run progresses, so a crash halfway through doesn’t cost the whole batch.
If it breaks: if fields come back None across the board, TikTok shipped a frontend change. Diff the page structure against a manual browser load before assuming your proxies are the problem.
8. Monitor and adapt
Log your block rate, verification challenges served divided by total requests, per proxy batch and per hour. A rising block rate is your earliest signal that a subnet or account is burning out, well before you get an actual stack trace.
Expected output: a daily count you can eyeball, block rate should sit under 5 to 10 percent on healthy residential proxies.
If it breaks: if block rate spikes past 30 percent, stop the run. Pushing through a hot streak of blocks tends to get the whole subnet flagged, not just the one session.
common pitfalls
- Using datacenter proxies to save money. It’s a false economy, you’ll get blocked in minutes and end up paying for the residential plan anyway after wasting the datacenter budget.
- No jitter between requests. A fixed interval is an easy bot signature. Randomize it every time.
- Not tracking account health. Logged-in accounts get shadowbanned quietly, feeds go stale or empty rather than throwing an obvious error, and you won’t notice until your data has holes in it.
- Treating the scraper as set-and-forget. TikTok changes its DOM and page-data structure periodically. Budget maintenance time the same way you’d budget it for any integration against a third-party API you don’t control.
- Storing full video files instead of just metadata. For market research you almost never need the actual video bytes, and downloading them multiplies your bandwidth bill for no analytical benefit.
scaling this
At 10x your starting volume, the main change is going from a handful of manually managed proxy IPs to a proper rotating pool with session stickiness, and moving the script from something you run by hand to a scheduled job.
At 100x, you need a queue (Redis or a simple job table works) feeding multiple worker processes, each with its own proxy session, plus a pool of several accounts instead of one or two so no single login absorbs all your login-gated requests. Cost scales roughly linearly with proxy bandwidth here, so this is where it’s worth negotiating volume pricing with your provider instead of paying list rate.
At 1000x, you’re managing proxy subnet health, account pool health, and rate limits per target endpoint as separate operational concerns, not one script’s problem. This is also where the account side starts to look less like scraping and more like managing a fleet of identities, which is a different discipline with its own tooling; the writeups on multiaccountops.com/blog/ are a decent reference for the session and identity management thinking once you’re running dozens of accounts in parallel rather than two or three. Mobile proxies also become worth the extra cost at this tier since they rotate carrier-side IPs that residential pools can’t match for volume.
where to go next
If you’re building scraping infrastructure across platforms rather than just TikTok, two other guides here cover adjacent ground: how to scrape Instagram at scale in 2026 walks through a lot of the same rotation logic against a different set of defenses, and best proxies for scraping LinkedIn in 2026 is worth reading if your research spans professional profiles too. For everything else covered on the site, check the blog index.
Written by Xavier Fok
disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-07-16.