1. 2scraper
  2. Social media & video
  3. TikTok Profile
Open source · MITRuns with no key, proxy or account

TikTok Profile Scraper

Exact follower, like and video counts, bio, verification and seller flags for any public TikTok account — no key needed.

  • Playwright
  • Selenium
  • Puppeteer
  • Plain HTTP
  • Scraping Browser API
  • JSON
  • CSV
tiktok-profile-scraper
# Single profile
$ ./venv/bin/python playwright_scraper.py --url nasa
✓ 3 sample rows · 41 columns in sample_output.json
41columns per account
0keys, proxies or accounts needed
1.54 sfor three accounts over plain HTTP, Sep 2026
4paths: plain HTTP, Playwright, Selenium, Puppeteer
Available TikTok Profile scrapers

What the TikTok Profile scraper collects

Extracts public statistics from TikTok profile pages: exact follower, following, like and video counts, the bio and its link, verification, organisation and TikTok Shop seller flags, account creation date and the settings a creator publishes — 41 columns per account. The default transport is plain HTTPS, with a browser fallback when TikTok actually challenges. Output is JSON or CSV with a .meta.json sidecar.

Single profile

Input: A handle, an @handle, or a full profile URL

One row with the account's exact counts from statsV2, bio, bio link, verification, seller flags, creation date and published settings.

Many profiles in parallel

Input: A comma-separated list of handles or URLs

One row per account, fetched concurrently; handles TikTok has no account for are listed in the sidecar's handles_unavailable rather than reported as a block.

Without a local browser

Input: A handle, via the 2Captcha Scraper API

The same row shape fetched through 2Captcha's Scraper API, for running where no browser and no direct connection are wanted.

Quick start

From zero to TikTok Profile data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/tiktok-profile-scraper
    $ cd tiktok-profile-scraper
    $ python3 -m venv venv
    $ ./venv/bin/pip install -r requirements.txt -r requirements-playwright.txt
    $ ./venv/bin/python playwright_scraper.py --url nasa
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ ./venv/bin/python playwright_scraper.py --url nasa
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

TikTok Profile data fields

41 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
user_idPermanent numeric account id, the join key (also in sku)
usernameThe @handle, which the account can change
sec_uidTikTok's own per-account token
follower_countExact follower count, from statsV2
following_countAccounts this one follows
likes_countTotal likes received
video_countNumber of videos
likes_per_videolikes_count / video_count; null with no videos
stats_sourcestatsV2, stats or absent — which object the counts came from
verifiedVerification badge
is_sellerTikTok Shop seller flag
bioProfile bio text
bio_linkThe link in the bio, where set
avatar_idStable content hash of the avatar; changes only when the picture does
created_atAccount creation date, ISO-8601 UTC
private_accountWhether the account is private
[
  {
    "source": "tiktok.com",
    "scraped_at": "2026-09-22T14:51:09Z",
    "url": "https://www.tiktok.com/@nasa",
    "sku": "7664638705177150477",
    "title": "NASA",
    "username": "nasa",
    "user_id": "7664638705177150477",
    "sec_uid": "MS4wLjABAAAAU9BRVzC8oCaegVnia8IbqWhPb_-dbU7s00Y3wS1_Nx8g5RUaYvyXrpejgjdxTwd6",
    "follower_count": 1785780,
    "following_count": 23,
    "likes_count": 9419647,
    "video_count": 46,
    "friend_count": 17,
    "digg_count": 0,
    "likes_per_video": 204774.93,
    "stats_source": "statsV2",
    "verified": true,
    "private_account": false,
    "is_organization": true,
    "is_seller": false,
    "commerce_user": false,
    "secret": false,
    "bio": "Making the seemingly impossible, possible.✨",
    "bio_link": null,
    "avatar_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/e5143212a59c09a008bf50f487…",
    "avatar_id": "e5143212a59c09a008bf50f487d54d1f",
    "avatar_expires_at": "2026-09-24T14:00:00+00:00",
    "language": "en",
    "created_at": "2026-07-20T15:55:49+00:00",
    "nickname_modified_at": "2026-07-20T15:58:00+00:00",
    "comment_setting": 0,
    "duet_setting": 0,
    "stitch_setting": 0,
    "download_setting": 0,
    "following_visibility": 1,
    "open_favorite": false,
    "show_playlist_tab": true,
    "status": "ok",
    "status_code": 0,
    "page": 1
  },
  {
    "source": "tiktok.com",
    "scraped_at": "2026-09-22T14:51:09Z",
    "url": "https://www.tiktok.com/@khaby.lame",
    "sku": "127905465618821121",
    "title": "Khabane lame",
    "username": "khaby.lame",
    "user_id": "127905465618821121",
    "sec_uid": "MS4wLjABAAAAwAg0rSzO65WQfz4RzQgGv2Xdv108BgPXhRrrmNVIHQZ9PO8-flwwRtEppYTS0OjA",
    "follower_count": 162986056,
    "following_count": 81,
    "likes_count": 2680889555,
    "video_count": 1353,
    "friend_count": 77,
    "digg_count": 0,
    "likes_per_video": 1981440.91,
    "stats_source": "statsV2",
    "verified": true,
    "private_account": false,
    "is_organization": false,
    "is_seller": false,
    "commerce_user": false,
    "secret": false,
    "bio": "Se vuoi ridere sei nel posto giusto😎 If u wanna laugh u r in the right place😎",
    "bio_link": null,
    "avatar_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/08987e23b94057953fd4f17386…",
    "avatar_id": "08987e23b94057953fd4f1738694bf5f",
    "avatar_expires_at": "2026-09-24T14:00:00+00:00",
    "language": "en",
    "created_at": "2016-08-10T22:02:34+00:00",
    "nickname_modified_at": null,
    "comment_setting": 0,
    "duet_setting": 0,
    "stitch_setting": 0,
    "download_setting": 0,
    "following_visibility": 1,
    "open_favorite": false,
    "show_playlist_tab": false,
    "status": "ok",
    "status_code": 0,
    "page": 1
  }
]

First 2 of 3 rows from a real run — sample_output.json. Long values shortened here.

Built for TikTok Profile

Handles what breaks naive TikTok Profile scrapers

Exact counts, not rounded ones

Every profile carries a stats object rounded to three significant figures (up and down — @tiktok was off by 43,287) and an exact statsV2. Every row reads statsV2, and stats_source plus the sidecar make a run of rounded numbers visible.

Plain HTTP first, browser when challenged

Profiles are server-rendered, so plain HTTPS took 1.54 s against the browser's 3.38 s for identical rows. --transport auto starts a browser the moment TikTok's WAF interstitial appears, which a browser cleared 3 of 3 times.

Stable avatar tracking

The avatar URL is re-signed on every request and 403s without its signature. avatar_id, the stable content hash, is what diff_runs.py tracks, and avatar_expires_at says when the link dies.

"User banned" is not a block

TikTok answers a nonexistent handle with HTTP 200 and "user banned". The run lists it in handles_unavailable, exits 4 if nothing else was found, and never reports it as a block.

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Scraping Browser API

Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete TikTok Profile snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with TikTok Profile data

Influencer vetting

Compare exact follower, like and video counts, likes per video and verification across a list of creators.

Audience growth tracking

Run the same handles daily and diff exact counts by the permanent user_id, even if a handle changes.

TikTok Shop seller discovery

Flag accounts that are TikTok Shop sellers or commerce users, as a starting point for tiktok-shop-scraper.

Brand and organisation monitoring

Track organisation accounts' bios, bio links and published comment, duet and stitch settings over time.

Access & pricing

Free to run. Pay only for what the site requires.

Runs with no key, proxy or account

A TikTok profile page is server-rendered and served to anyone: measured 2026-09-22 from a bare datacentre address, plain curl and headless and headful Chromium were all served, and the daily canary runs with no secrets. A residential proxy was measured worse than none on this route (2 of 9 exits served to a plain HTTP client). 2Captcha's products buy volume from many addresses, a specific exit country and no browser infrastructure of your own — not access.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • A nonexistent handle and a banned account get the same answer from TikTok, and this repo does not claim to tell them apart.
  • The signed avatar_url expires about 48 hours after the run.
  • Selenium cannot use an authenticated CDP endpoint or proxy.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

TikTok Profile scraper FAQ

Do I need a TikTok account, key or proxy?

No. For fewer than a few thousand accounts from one address, the README says you need none of the paid products.

Why do my counts differ from other tools?

Most read TikTok's rounded stats object. This repo reads the exact statsV2 object; the README shows rounding errors of up to tens of thousands of followers on large accounts.

Why do two runs an hour apart differ?

The counts move: nine refetches of one account within an hour returned nine different follower counts. diff_runs.py reports those as real changes.

Does it scrape an account's videos?

No. The profile's video-grid API answered HTTP 200 with an empty body to every variant tried, so this repo reports that as blocked; videos are covered by tiktok-video-scraper from the embed route and video pages.

What does --locale change?

Only the page chrome. ?lang=ja and ?lang=ar returned byte-identical account data.

Is scraping TikTok profiles legal?

It reads public profile data any visitor is served. It is public data; follow TikTok's terms and the law where you operate.