# TikTok Profile Scraper (`socialdataapi/tiktok-profile-scraper`) Actor

Scrape public TikTok creator profiles by username. Returns one row per video with views, likes, comments, shares, caption, hashtags, sound, video metadata, cover image and play/download URLs. No login required.

- **URL**: https://apify.com/socialdataapi/tiktok-profile-scraper.md
- **Developed by:** [Social Data API](https://apify.com/socialdataapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.79 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### TikTok Profile Scraper — Views, Likes, Captions and Video URLs

TikTok Profile Scraper extracts the public video feed of any TikTok creator and returns one structured JSON row per video: view, like, comment and share counts, the caption with parsed hashtags, sound name and artist, video dimensions and duration, cover images, and direct play/download URLs, plus the creator's handle, nickname, verified flag and avatar. 19 keys per row, no HTML parsing, no TikTok login. Paste usernames or profile URLs and press Start.

![TikTok Profile Scraper: views, likes, comments, shares and captions for every video as JSON](https://api.apify.com/v2/key-value-stores/WYkyEfqs10huyXYxr/records/tiktok-profile-hero.webp)

Open this Actor on the Apify Store: [apify.com/socialdataapi/tiktok-profile-scraper](https://apify.com/socialdataapi/tiktok-profile-scraper).

⚠️ **This Actor writes one row per video, not one row per profile.** There is no profile-only mode: the creator's handle and nickname are repeated on every video row, and a creator with no videos produces an uncharged error row instead of a profile record. If you want a single record per creator, take the first row per `author.username` and ignore the video fields.

TikTok Profile Scraper is an Apify Actor that loads a public TikTok profile page, reads the creator's identity out of the page's own embedded data, then pages through TikTok's public video feed to build one flat, typed dataset row per video. No TikTok account, login, password or session cookie is required, and none is accepted: it sees only what a signed-out visitor is served, and every request it makes is generated fresh per run rather than lifted from a signed-in session.

It is built for influencer marketers vetting creators, social analysts benchmarking content performance, growth teams tracking hashtag and sound usage, and developers piping video-level engagement into a warehouse, dashboard or AI agent.

### What data can I extract with TikTok Profile Scraper?

TikTok serves a signed-out visitor a public creator's basic identity and video grid — handle, nickname, avatar and verified badge, and every video with its own caption, sound and engagement counters. What it withholds is relationship lists, private and friends-only content, age-gated videos and anything belonging to a private account.

#### What data is publicly available to scrape?

| Data Category | Signed-out visitor | Gated behind a TikTok login or the account owner |
| ----- | ----- | ----- |
| Handle, nickname, avatar | ✅ Public | — |
| Verified badge | ✅ Public | — |
| Video grid: caption, views, likes, comments, shares | ✅ Public | — |
| Sound name, sound author, original-sound flag | ✅ Public | — |
| Video dimensions, duration, cover images, play/download URLs | ✅ Public | — |
| Follower count, following count, total likes, bio | Publicly visible on the profile page | Not part of this Actor's output |
| Friends-only, private and draft videos | ❌ | Account owner only |
| Age-restricted videos and region-blocked content | ❌ | Login and region eligibility |
| Anything on a private account | ❌ | Approved follow required — never returned |
| Direct messages and Creator Center analytics | ❌ | Account owner only |
| Comment text under each video | Publicly visible | Not part of this Actor's output — see TikTok Comments Scraper |

TikTok Profile Scraper only returns publicly visible data — what any signed-out visitor sees on the profile page. Nothing behind a login wall.

Every charged row carries four things: which video it is, what the caption says, how it performed, and what sound and video file sit behind it.

| Field Name | Description |
| ----- | ----- |
| `id` | TikTok's numeric video id, as a string. A row without one is never pushed |
| `input` | The handle this row was collected for — `@` stripped, URL resolved. Not necessarily the literal string you passed |
| `url` | Canonical video URL, rebuilt as `https://www.tiktok.com/@{handle}/video/{id}` |
| `title` | The caption, or `"TikTok video #{id}"` when the video has no caption |
| `description` | Full caption text, line breaks and emoji preserved. `""` when the video has no caption |
| `create_time` | Video timestamp as a raw Unix epoch integer |
| `duration` | Video length in seconds |
| `width` | Video width in pixels |
| `height` | Video height in pixels |
| `cover_url` | Static cover image URL |
| `dynamic_cover_url` | Animated cover image URL |
| `play_url` | Direct video stream URL |
| `download_url` | Direct video download URL |
| `author` | `{ "username", "nickname", "avatar", "verified" }` — the creator who posted this specific video (usually, but not always, the handle you asked for — see the FAQ on renamed handles) |
| `stats` | `{ "views", "likes", "comments", "shares" }` — integers as TikTok returns them |
| `music` | `{ "title", "author", "duration" }` for the sound used |
| `hashtags` | Array of strings parsed from the caption's tag entities |
| `scrapedAt` | UTC ISO-8601 timestamp for when the row was written |
| `runId` | The Apify run id that produced the row, or `null` if unavailable |

19 keys are written on every charged video row. `errorReason` is the only key that appears on uncharged rows and never on a charged one, which is what makes it the clean thing to filter on.

#### Nested objects: author, stats and music

`author`, `stats` and `music` are plain nested objects, not flattened. `stats` is read as TikTok returns it, with no type coercion — if a counter is ever missing it defaults to `0`, but the Actor otherwise passes the number through unchanged. `hashtags` is built from the caption's tag entities rather than a regex over the text, so a tag with punctuation or a non-Latin script still gets picked up as its own entry.

#### 🤖 Add-on: Need additional TikTok data?

A video feed answers "what did this creator publish, and how did it do". **TikTok Comments Scraper By Real Comment Filter** takes the `url` values from these rows and pulls the discussion under each one, filtered down to real comments. **Tiktok Video Scraper (Creator Profile & Contact)** works the other way around — start from individual video URLs and get the creator's profile and public contact details attached. For discovery rather than a known handle, **TikTok Trending Hashtags Scraper By Multiple Countries** and **Tiktok Trending Hashtags Analytics Scraper By Country** surface what is rising before you pick creators to track.

### How to use TikTok Profile Scraper

TikTok Profile Scraper runs on Apify. Start it from the Apify Console or call it through the Apify API — the only credential involved is your Apify token.

1. Open TikTok Profile Scraper on Apify and click **Try for free**
2. Add one or more entries to **TikTok profiles** (`profiles`) — this is the only required input. A bare handle, an `@handle` and a full profile URL all work
3. Set **Maximum videos per profile** (`resultsPerPage`) — default 10, maximum 50,000, or 0 for unlimited
4. Leave **Proxy** (`proxyConfiguration`) alone unless you see repeated blocks — the Actor escalates on its own
5. Click **Start**, then export the dataset as JSON, CSV, Excel or XML, or read it through the Apify API

A run with no `profiles` does not crash and does not fail. The Actor logs `No TikTok profiles supplied. Nothing to do.`, writes nothing at all — not even an error row — exits successfully, and charges nothing. The same happens if every entry you pass is blank. The Console blocks an empty submission because the field is required, so this only reaches callers that assemble the input JSON themselves.

#### How to scale to bulk TikTok profile extraction

`profiles` is a list, so bulk is the normal mode — add as many handles as you need in one run. Neither the input schema nor the code caps how many profiles a single run may contain; the practical ceiling is the memory and timeout you give the run on Apify. A comma-separated or newline-separated single string is also accepted and split for you, so a handle list produced by another tool usually feeds in unchanged.

Profiles are processed strictly one after another through one warm HTTP session, and every row for a profile is written before the next handle starts. Duplicates are **not** removed across your input list: the same handle twice is scraped twice and charged twice, so deduplicate before you run.

### ✨ Features

TikTok Profile Scraper fetches clean, structured video data from any public TikTok creator's feed ⚡ with no TikTok account, browser or cookie needed. It's ideal for influencer vetting, competitor content audits, hashtag and sound tracking, and feeding creator-research AI agents.

It extracts, per video:

- **View, like, comment and share counts** – engagement exactly as TikTok returns it, no coercion
- **Caption and parsed hashtags** – full caption text plus the tag entities TikTok attaches to it
- **Sound name and artist** – the `music` object on every video
- **Cover, play and download URLs** – direct links to the static cover, animated cover and the stream/download file
- **Creator identity** – handle, nickname, avatar and verified flag on every row
- **Stable, typed schema** – the same 19 keys on every charged row, independent of TikTok's front-end layout

⚡ No browser and no CAPTCHA solving — plain HTTP requests with automatic proxy escalation on a block keep runs light and fast.

### Use cases 💡

- 📊 **Influencer marketer** — compares `stats.likes` and `stats.comments` against `stats.views` across a creator's recent videos to see which posts over- or under-perform.
- 🎵 **Social strategist** — counts `music.title` and `music.author` across a competitor's videos to see which sounds they ride versus produce.
- 📈 **Content researcher** — exports `create_time`, `stats.views` and `duration` to correlate video length and posting time against views.
- 🖼️ **Creative team** — pulls `cover_url` and `play_url` for the most recent videos of ten creators in one run to build a swipe file.
- 🤖 **AI engineer** — indexes `description`, `hashtags` and `music.title` into a vector store with `author.username`, `stats.views` and `create_time` as metadata filters for a creator-research agent.

Building an AI agent? [Connect TikTok Profile Scraper over MCP](#mcp-integration-for-ai-agents) and let it call the actor on its own.

### Why choose this actor?

1. **A full profile scrape in under a minute.** A recorded run scraped 2 profiles end-to-end in 41.6 seconds, returning 8 charged video rows with no manual intervention.
2. **19 structured fields per video, not a raw blob.** A recorded row for @mrbeast's top video came back with 20,600,000 views, 2,900,000 likes, 72,300 comments and 66,700 shares, plus cover, play and download URLs, sound name and parsed hashtags.
3. **One input, three accepted formats.** Bare handles, `@handles` and full profile URLs all resolve to the same result, and a single run accepts any number of profiles with no per-run cap.

#### How does it compare to TikTok's official APIs?

TikTok publishes two developer APIs, and neither reads an arbitrary third-party creator's profile on demand. The **Display API** returns profile and video data only for users who have completed an OAuth login with your own registered app. The **Research API** is application-only, oriented toward academic and non-profit research, and access depends on an eligibility review. TikTok Profile Scraper reads the public profile page and its video feed instead, which is why it accepts any public handle with no approval step.

| Feature | TikTok Display API | TikTok Research API | TikTok Profile Scraper |
| ----- | ----- | ----- | ----- |
| Reads a creator you do not own and who has not authorised your app | ❌ Out of scope | Only within an approved research scope | ✅ Any public profile |
| Approval before you can start | App registration and review | Application plus eligibility review | ❌ None |
| Credential you supply | A registered app plus a user OAuth token | Approved research credentials | Your Apify token only |
| Per-video views, likes, comments and shares | For the authorising user's own videos | Within the approved scope | ✅ For every video fetched |
| Output shape | TikTok's documented API schema | TikTok's documented research schema | One flat row per video, stable key names |
| Setup path | Implement an OAuth flow | Submit an application and wait | Paste handles, press Start |
| Request budget | Published by TikTok — check its docs | Published by TikTok — check its docs | Bounded by your Apify run |

Verify every constraint above against TikTok's current published developer documentation before choosing — those terms change, and no quotas or rate figures are reproduced here. Use the official APIs when the accounts belong to your own users and you need a supported contract, or when you qualify for research access. Use TikTok Profile Scraper for competitive and creator research across accounts you have no authorisation over.

### ⬇️ Input

![TikTok Profile Scraper input: profiles, videos per profile and proxy](https://api.apify.com/v2/key-value-stores/WYkyEfqs10huyXYxr/records/tiktok-profile-input.webp)

Three parameters, one of them required. Everything below is read from the input schema as shipped.

| Parameter | Required | Type | Description | Example Value |
| ----- | ----- | ----- | ----- | ----- |
| `profiles` | Yes | array | TikTok usernames or profile URLs, one per line (`stringList` editor). A leading `@` and a full `https://www.tiktok.com/@handle` URL are both accepted. Prefilled with `["mrbeast"]`. No minimum or maximum count. | `["mrbeast", "@khaby.lame", "https://www.tiktok.com/@zachking"]` |
| `resultsPerPage` | No | integer | Upper bound on videos collected per profile. Minimum 0, maximum 50,000, default 10. `0` disables the cap and collects every video the profile has. Each page returns up to 15 videos, so higher values mean more sequential requests and longer runs. Free plan: up to 20 videos per run (all profiles together) and 200 per month; paid plans have no limit. | `100` |
| `proxyConfiguration` | No | object | Apify Proxy settings (`proxy` editor). Prefilled with `{"useApifyProxy": false}` — the direct container IP. The Actor escalates to a datacenter and then a residential proxy on its own if a profile is blocked. | `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` |

Three honest notes on how these behave, all of which matter more to API callers than to Console users:

- **Every advertised `profiles` format really parses.** A bare handle (`mrbeast`), an `@handle` (`@khaby.lame`), a full profile URL, a URL with a query string, and a URL with a trailing slash all resolve to the same handle. So does an individual video URL — `https://www.tiktok.com/@zachking/video/7301…` collapses to `zachking` — and so does the short `tiktok.com/mrbeast` form. The one thing to avoid is a non-profile TikTok URL: a hashtag or sound page reduces to its last path segment, which is then treated as a handle and produces an error row.
- **`0` means unlimited; omitting the field does not.** Omit `resultsPerPage` (or send `null` or a non-numeric value) and you get the default, 10. Send `0` explicitly and the cap is disabled — the Actor collects every video it can reach for that profile. Any other out-of-range value is clamped to 1–50,000 by the code rather than rejected.
- **`proxyConfiguration` genuinely defaults to no proxy.** The shipped prefill is `{"useApifyProxy": false}`, meaning a direct connection on the container IP. If your own proxy configuration fails to build, the Actor logs a warning and continues on the direct IP rather than failing the run.

#### Free plan limits

Free plan: up to 20 videos per run (all profiles together) and 200 per month; paid plans have no limit. A free-plan run with several profiles shares that same 20-video ceiling across all of them, not 20 per profile — the Actor stops the whole run once the run total is reached and tells you so in the log and status message. Paid plans, local `apify run`s and Apify's own test runs are never limited.

#### Example input

```json
{
  "profiles": [
    "mrbeast",
    "@khaby.lame",
    "https://www.tiktok.com/@zachking"
  ],
  "resultsPerPage": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

### ⬆️ Output

![TikTok Profile Scraper output: stats, author, music and hashtags on every video row](https://api.apify.com/v2/key-value-stores/WYkyEfqs10huyXYxr/records/tiktok-profile-output.webp)

Typed, normalized JSON with a consistent shape across runs — one row per video, 19 top-level keys on every charged row, with `author`, `stats` and `music` carried as nested objects. Rows are written as each profile is scraped, so the dataset fills while the run is still going. Export as JSON, CSV, Excel or XML from the Console, or read the dataset through the Apify API.

**On charging and uncharged rows.** Each video row is pushed with one `row_result` charged event. A profile that cannot be read, or that has zero videos, instead produces a single **uncharged accounting row**, pushed with no charged event at all. Those rows are the only ones that carry `errorReason`, so that key is the filter:

```python
items  = list(client.dataset(run["defaultDatasetId"]).iterate_items())
videos = [r for r in items if not r.get("errorReason")]
errors = [r for r in items if r.get("errorReason")]
```

An uncharged row carries 6 keys and no nested objects: `id` (as `error-<handle>`), `input`, `url` (the profile URL, not a video URL), `errorReason`, `scrapedAt` and `runId`. The `errorReason` values the Actor emits are `blocked` (the profile page never cleared TikTok's anti-bot checks), `not_found_or_private` (no usable profile data at all — wrong, renamed-away or private handle), `network_error` (transient connectivity failure), `no_videos` (the profile resolved but has no videos), and `unexpected_error: <message>` for anything else.

#### Example output

One charged video row:

```json
{
  "id": "7634583942254972190",
  "input": "mrbeast",
  "url": "https://www.tiktok.com/@mrbeast/video/7634583942254972190",
  "title": "We're just one big happy family :)",
  "description": "We're just one big happy family :)",
  "create_time": 1777565126,
  "duration": 14,
  "width": 720,
  "height": 1280,
  "cover_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-useast8-p-0068-tx2/oocfcAAeTHIMAMMmErLIAuGJI5AjMRAQI2elqv~tplv-tiktokx-origin.image",
  "dynamic_cover_url": "https://p16-common-sign.tiktokcdn-eu.com/tos-useast8-p-0068-tx2/oocfcAAeTHIMAMMmErLIAuGJI5AjMRAQI2elqv~tplv-tiktokx-origin.image",
  "play_url": "https://v16-webapp-prime.tiktok.com/video/tos/maliva/tos-maliva-ve-0068c799-us/oUHUEHmERVzfizXOfAg3JIX8QA1pqnDNHadEFB/",
  "download_url": "https://v16-webapp-prime.tiktok.com/video/tos/maliva/tos-maliva-ve-0068c799-us/okcjP5IvVNrHJNq6Inm1e0AgGeAeLIAoECwTvR/",
  "author": {
    "username": "mrbeast",
    "nickname": "MrBeast",
    "avatar": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/1e2348ca19d394037718e3b1d3fc2958~tplv-tiktokx-cropcenter:720:720.jpeg",
    "verified": true
  },
  "stats": {
    "views": 14100000,
    "likes": 1200000,
    "comments": 69000,
    "shares": 43100
  },
  "music": {
    "title": "original sound",
    "author": "MrBeast",
    "duration": 14
  },
  "hashtags": [],
  "scrapedAt": "2026-10-11T09:41:07Z",
  "runId": "kPq2xR7bNvL4mTz1a"
}
```

And one uncharged row, for a handle that turned out to be private:

```json
{
  "id": "error-privatecreator99",
  "input": "privatecreator99",
  "url": "https://www.tiktok.com/@privatecreator99",
  "errorReason": "not_found_or_private",
  "scrapedAt": "2026-10-11T09:41:22Z",
  "runId": "kPq2xR7bNvL4mTz1a"
}
```

### How does it work?

TikTok builds a profile page from structured data embedded in the page itself, and it builds the video grid from a separate feed. TikTok Profile Scraper fetches the profile page with a plain HTTP request, reads the creator's identity out of the page's own embedded data, then pages the video feed with a descending timestamp cursor until it has the number of videos you requested or TikTok reports no more.

Each raw video is mapped onto fixed key names by explicit path, so a key TikTok moves degrades one field instead of breaking the row. Because the data comes from JSON rather than CSS selectors, a TikTok front-end redesign does not change your field names.

Only publicly visible data is returned. There is no login, no cookie and no session anywhere in the flow, so private accounts and friends-only videos are out of reach by design rather than by omission.

#### How does it handle blocking?

TikTok does not always answer a blocked request with an HTTP error — a block can come back as a normal-looking response that is actually a short, generic challenge page instead of the profile's real content. So this Actor never keys block detection on status code alone — it checks whether the response actually contains the profile's real data.

Transport is a plain HTTP session, with no browser involved, tuned to behave like a real desktop browser so it is not rejected outright for looking like a script. On a block the Actor opens a fresh session and, after a couple of failed attempts, climbs a proxy tier — direct → Apify datacenter → Apify residential — logging each switch. Resolving a profile gets up to 30 attempts, with a growing pause between each; each video feed page gets up to 3. There is **no CAPTCHA solving** in this Actor, and none is claimed.

When a profile cannot be read at all, the run does not stop. The Actor writes one uncharged error row naming the reason and moves on to the next handle.

### How do you integrate TikTok Profile Scraper into your stack?

TikTok Profile Scraper works with what you already use: a REST API callable from any language, MCP for AI agents, and no-code automation tools.

#### Using TikTok Profile Scraper with the Apify API

```python
import requests

resp = requests.post(
    "https://api.apify.com/v2/acts/socialdataapi~tiktok-profile-scraper/run-sync-get-dataset-items",
    params={"token": "YOUR_APIFY_TOKEN"},
    json={
        "profiles": ["mrbeast", "@khaby.lame", "https://www.tiktok.com/@zachking"],
        "resultsPerPage": 100,
    },
)

for video in resp.json():
    if video.get("errorReason"):
        continue
    print(video["author"]["username"], video["stats"]["views"], video["url"])
```

*Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request.*

#### MCP integration for AI agents

TikTok Profile Scraper (Apify Actor ID: socialdataapi/tiktok-profile-scraper, https://apify.com/socialdataapi/tiktok-profile-scraper) is callable over the Model Context Protocol through Apify's MCP server.

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=socialdataapi/tiktok-profile-scraper"
```

This registers TikTok Profile Scraper as a tool your agent can call directly, once it finds the Actor through the server's search, add and call-actor tools. Compatible with Claude Code, Cursor and Windsurf.

#### No-code tools (n8n, Make, LangChain)

In n8n, use the Apify node — or an HTTP Request node pointed at the Actor's run endpoint with your token — and pass the same JSON input shown above; add an IF node on `errorReason` and the flat rows drop straight into a Google Sheets or Postgres node. In Make, the Apify module supports run-and-wait, so a weekly creator-performance refresh can feed an Airtable step with no glue code. In LangChain, wrap the run endpoint as a tool and hand the rows to the model directly, since they are already typed JSON. Apify schedules and webhooks cover recurrence and completion triggers, so a monthly snapshot of a creator list needs nothing of your own.

### Is it legal to scrape TikTok data?

Scraping publicly visible profile and video data is broadly treated as permissible where no login is used and no private account is accessed, and TikTok Profile Scraper does neither — it reads only what a signed-out visitor is served, and private accounts are inaccessible to it.

**This output contains personal data about identifiable individuals.** `author.username`, `author.nickname` and `author.avatar` describe a real person. `description` frequently names people, and `cover_url`, `play_url` and `download_url` point at images and video of identifiable individuals.

Under GDPR, UK GDPR and CCPA you need a lawful basis before you store or reuse any of it. If you rely on legitimate interests, document the balancing test — your specific purpose, why scraped public data is necessary for it, and why the creators' rights and expectations are not overridden — before ingestion rather than after. Apply data minimisation at ingestion too: for engagement benchmarking, keep `author.username` and the `stats` fields and drop the heaviest personal-data payload first — `author.avatar`, `cover_url`, `play_url` and `download_url`. Set a retention period that matches that purpose instead of warehousing rows indefinitely, be transparent in your privacy notice about collecting public TikTok data, and keep the `author.username`-to-row mapping you would need to answer an access, objection or erasure request.

Consult legal counsel if your use case involves bulk storage of personal data.

### Frequently asked questions

#### What TikTok profile fields does TikTok Profile Scraper return?

The five most used are `author.username`, `stats.views`, `stats.likes`, `description` and `create_time`. Every charged row carries 19 top-level keys, including the nested `author`, `stats` and `music` objects and the parsed `hashtags` array — see the data fields table above for all of them.

#### Does TikTok Profile Scraper require a TikTok account, login or session cookie?

No. There is no login, no password and no cookie anywhere in the input schema or the code, and none can be supplied. Every identifier the Actor sends is generated fresh per run rather than lifted from a signed-in session, so nothing about a run is tied to an account. The only credential you need is your Apify token. The trade-off is that anything TikTok serves only to a logged-in session — follower lists, friends-only videos, age-gated content, private accounts — is out of reach.

#### How many videos can I extract per profile in one run?

Up to 10 per profile by default, up to 50,000 if you raise `resultsPerPage`, or unlimited if you set it to `0` — the Actor then keeps paging a profile until TikTok's feed runs out, instead of stopping at a count. The 50,000 ceiling only applies when you give an explicit nonzero value above it; it is clamped rather than rejected. Each page returns up to 15 videos, so a 500-video run means roughly 34 sequential requests with a 1–2 second randomised pause between them — an unlimited run on a prolific account takes proportionally longer. There is no cap at all on how many profiles one run may contain.

#### What happens if a profile is private, does not exist, or was renamed?

Every case produces an uncharged row rather than a crash or a silent gap, and the run continues with the next handle.

A profile the Actor could never resolve — because it is **private**, does not exist, was deleted, or TikTok's anti-bot checks never cleared after repeated attempts — produces `errorReason: "not_found_or_private"` or `"blocked"`. A profile that resolved but has zero videos produces `"no_videos"`. A transient connection failure produces `"network_error"`.

A **renamed** handle usually still resolves, because TikTok redirects the old handle. Compare `input` (what you typed) against `author.username` (what TikTok's own video payload returned): when they disagree, the account was renamed. If the old handle no longer resolves at all, you get `"not_found_or_private"`.

#### Am I charged for profiles that fail?

No. Only video rows are pushed with the `row_result` charged event. Error and accounting rows are pushed with no charged event at all, and they are the only rows carrying `errorReason`, so `if not row.get("errorReason")` separates what you paid for from what you did not. A run whose `profiles` list is empty pushes nothing and charges nothing.

#### Can I scrape multiple TikTok profiles at once?

Yes. `profiles` is a list and there is no cap on its length in the schema or the code. Bare handles, `@handles`, full profile URLs and even individual video URLs can be mixed freely in the same list, and a single comma- or newline-separated string is split for you. Two caveats: duplicates are not removed, so the same handle twice is scraped twice and charged twice, and profiles run sequentially rather than in parallel, so a very long list is better split across scheduled runs than pushed into one.

#### Does TikTok Profile Scraper work with Claude, ChatGPT and other AI agent tools?

Yes. It is callable as a standard HTTP-triggered Apify run, so LangChain, CrewAI, n8n or a hand-written tool definition can start it and read back typed JSON with no parsing step. Give the agent one rule: skip rows where `errorReason` is present, because those are uncharged failure markers rather than videos.

#### How does TikTok Profile Scraper compare to other TikTok profile scrapers?

This Actor returns one row per video with a compact, typed field set (see the data fields table above) rather than a large nested shape with dozens of keys. Some competing listings return additional fields such as a bio link, follower counts per row, or a reposts feed; others return one row per profile instead of per video. Compare current field lists, scope and pricing directly on each listing's Apify Store page before choosing, since these change over time and are not reproduced here.

#### Does TikTok Profile Scraper return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with consistent field names across runs — no HTML parsing, no selectors. Pass a row straight into an LLM context window, index it into a vector store, or hand it to an agent tool. The row is flat except for `author`, `stats` and `music`, so unpack those three objects first if you want every value at the top level.

#### What happens when TikTok changes its layout or anti-bot system?

The scraper is maintained, and because it reads TikTok's own structured data and video feed rather than rendered markup, a front-end redesign generally does not affect your field names or types. Anti-bot pressure is the live surface, and it is handled by design rather than by hope: detection keys on whether the response actually carries real page content, not on HTTP status, and the response is a fresh session on a growing pause, then a proxy-tier climb. A failure surfaces in the log and in `errorReason` instead of quietly returning empty rows.

#### Can I use TikTok Profile Scraper without managing proxies or browser infrastructure?

Yes, and there is nothing to configure. There is no browser at all — the Actor uses plain HTTP requests, which is why runs are lighter than a headless-Chromium scraper. Proxying is automatic and cheapest-first: it starts on the direct container IP and climbs to an Apify datacenter and then residential proxy only if TikTok blocks a profile. You never install a browser, create a proxy account or rotate an IP. The Actor does not solve CAPTCHAs, and it makes no claim to.

#### Which TikTok fields work best for AI training data and RAG indexing?

For RAG, `description` is the highest-information field per record and chunks cleanly, with `hashtags` and `music.title` as topical metadata. For training data, the most structurally consistent fields across records are `stats.views`, `stats.likes`, `stats.comments`, `stats.shares`, `duration` and `create_time` — typed primitives read directly from TikTok's response. Presence-check before feeding any of them to a model, since a field TikTok omits for a given video comes through as an empty string or `0` rather than being dropped.

### Related scrapers

| Scraper Name | What it extracts |
| ----- | ----- |
| TikTok Comments Scraper By Real Comment Filter | Comment threads under TikTok videos, filtered to real comments |
| Tiktok Video Scraper (Creator Profile & Contact) | Single-video data with the creator's profile and public contact details attached |
| TikTok Trending Hashtags Scraper By Multiple Countries | Rising TikTok hashtags across several countries in one run |
| Tiktok Trending Hashtags Analytics Scraper By Country | Trending-hashtag analytics for a single country and industry |
| Instagram Profile Scraper | The same identity and follower fields for Instagram, one row per profile |
| Snapchat Profile Scraper | Public Snapchat profiles — display name, bio, subscriber count, snapcode |

Which one suits which job: use **TikTok Profile Scraper** when a creator's video feed is the record you want, with per-video engagement attached. Use **Tiktok Video Scraper (Creator Profile & Contact)** when you already have specific video URLs and want the creator behind them. Use **TikTok Comments Scraper By Real Comment Filter** when the audience reaction matters more than the video metrics.

### Your feedback

Found a bug, or need a field that is in TikTok's video payload but not in this output — comment text, follower counts, reposts, the profile bio link? Open an issue on the Actor's Issues tab. Reports that include the exact input JSON and the handle you ran are the fastest to reproduce and fix.

# Actor input Schema

## `profiles` (type: `array`):

TikTok usernames or profile URLs, one per line. A leading @ and a full https://www.tiktok.com/@handle URL are both accepted.

## `resultsPerPage` (type: `integer`):

Upper bound on videos collected per profile. Each page request returns up to 15 videos, so higher values mean more sequential requests and longer runs. Set to 0 to disable the cap and collect every video the profile has (unlimited). Free plan: up to 20 videos per run (all profiles together) and 200 per month; paid plans have no limit.

## `proxyConfiguration` (type: `object`):

Optional. Runs can succeed on the direct datacenter IP; enable a proxy only if you see repeated blocks. The actor escalates to a datacenter and then a residential proxy on its own if a profile is blocked before any row is produced.

## Actor input object example

```json
{
  "profiles": [
    "mrbeast"
  ],
  "resultsPerPage": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped items in the Actor's default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "profiles": [
        "mrbeast"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("socialdataapi/tiktok-profile-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "profiles": ["mrbeast"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("socialdataapi/tiktok-profile-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "profiles": [
    "mrbeast"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call socialdataapi/tiktok-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,socialdataapi/tiktok-profile-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/mJKH67WZbb2hKFqA7/builds/UdhZQZzAQvyeLUBfV/openapi.json
