# Fast Tiktok Profile Scraper 🚀 (`aimscrape/tiktok-profile-scraper`) Actor

Extract public TikTok profile data from usernames or profile URLs. Collect bios, avatars, follower and following counts, total likes, video counts, and verification status when available. Compare creator accounts and build profile directories.

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

## Pricing

from $0.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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

### What does TikTok Profile Scraper do?

**TikTok Profile Scraper** extracts profile metadata from [TikTok](https://www.tiktok.com/) usernames and profile URLs. Get bios, avatars, follower and following counts, total likes, video counts, and verification status in a structured dataset you can export or retrieve through the Apify API.

The Actor reads publicly returned profile information without logging in to TikTok. It collects profile metadata only; it does not download videos or collect follower lists.

### How to scrape TikTok profiles

1. Open the **Input** tab and add usernames or full profile URLs to **TikTok usernames or profile URLs**.
2. Start the Actor. For your first run, use a few profiles to check the available data.
3. Follow progress in the run log, then open **Profiles** in the **Output** tab to review the results.
4. Download the dataset as **JSON, CSV, or Excel**, or another format supported by Apify.

Use the Actor's **API** tab for programmatic runs and Apify scheduling for recurring collection. Each run captures the data returned at collection time; compare datasets from separate runs to track changes.

### Why use TikTok Profile Scraper?

- **Compare creator accounts:** review audience size, total likes, video counts, and verification status.
- **Maintain a profile directory:** collect consistent usernames, account IDs, bios, avatars, and public bio links.
- **Track account statistics:** schedule repeat runs and use the collection timestamps in your reports.

### Input

```json
{
  "usernames": [
    "https://www.tiktok.com/@tiktok",
    "@example_user"
  ],
  "skipInvalidInputs": true
}
```

`usernames` is required and accepts **1 to 100,000 entries**. You can mix these formats in the same list:

| Format | Example |
| --- | --- |
| Username | `tiktok` |
| Username with an `@` prefix | `@tiktok` |
| HTTPS profile URL | `https://www.tiktok.com/@tiktok` |

Profile URLs must use `tiktok.com` or `www.tiktok.com`; a trailing slash is allowed. Video URLs, short links, URLs with query parameters or fragments, numeric user-ID lookup, surrounding spaces, and other websites are not supported. A numeric string is interpreted as a username.

The Actor validates each string locally before creating requests. Valid and invalid entries can coexist in one list: valid targets continue normally, while invalid entries never make TikTok requests. By default, `skipInvalidInputs` is `true`, so invalid entries are omitted from the Dataset. Set it to `false` to store one `invalid_input` row per distinct invalid string. Recognizable credentials in stored invalid strings are redacted before output.

Usernames are normalized to lowercase and duplicate targets are collected once per new run, including different input forms for the same account. For example, `tiktok`, `@TikTok`, and `https://www.tiktok.com/@tiktok` identify one target. See [Stopping and resuming a run](#stopping-and-resuming-a-run) for recovery limitations.

### What data can TikTok Profile Scraper extract?

| Field | Type | Meaning |
| --- | --- | --- |
| `status` | string | `ok`, `not_found`, `restricted`, or `invalid_input`. |
| `id` | string or null | TikTok user ID, preserved as text. |
| `username` | string | Normalized requested username, or the redacted submitted string for an `invalid_input` row. |
| `url` | string or null | Canonical profile URL, or `null` for an `invalid_input` row. |
| `nickname`, `bio` | string or null | Display name and profile biography. |
| `secUid` | string or null | Secondary public user identifier. |
| `avatarUrl` | string or null | Best available profile avatar URL. |
| `verified`, `privateAccount` | boolean or null | Account flags returned by TikTok. |
| `followerCount`, `followingCount` | integer or null | Follower and following counts. |
| `heartCount` | integer or null | Total likes reported for the account. |
| `videoCount`, `friendCount` | integer or null | Video and friend counts when returned. |
| `bioLink`, `region` | string or null | Public bio link and reported region, when available. Region is not an inferred location. |
| `crawledAt` | string | UTC collection timestamp in ISO 8601 format. |

Every row includes all fields, including `not_found` and `restricted` rows. **Missing optional values are `null`; reported zero counts remain zero.** Keep `id` as text when importing results into spreadsheets or databases to preserve its precision.

### Output example

The following is **synthetic example data**, not a captured live account. It shows the complete profile record. The **Profiles** table highlights account identity and counts; JSON includes all fields.

```json
{
  "status": "ok",
  "id": "1234567890123456789",
  "username": "example_user",
  "url": "https://www.tiktok.com/@example_user",
  "nickname": "Example Creator",
  "bio": "Cooking and travel",
  "secUid": "example-sec-uid",
  "avatarUrl": "https://example.com/avatar.jpg",
  "verified": false,
  "privateAccount": false,
  "followerCount": 12500,
  "followingCount": 120,
  "heartCount": 450000,
  "videoCount": 85,
  "friendCount": 30,
  "bioLink": "https://example.com",
  "region": "SG",
  "crawledAt": "2026-10-25T09:00:00Z"
}
```

### Availability and partial results

| Status | Meaning |
| --- | --- |
| `ok` | TikTok returned profile data matching the requested account, including public metadata from private accounts. Private accounts have `privateAccount: true`; available fields are preserved and private videos are not accessed. |
| `not_found` | TikTok explicitly reported that the account could not be found or was unavailable, without returning user data. This does not distinguish a deleted account from a banned account or establish that the username is available to register. |
| `restricted` | TikTok reported region, age, audience, or Family Pairing controls that prevent profile access. The Actor records the outcome without extracting account metadata or attempting to access restricted content. |
| `invalid_input` | The submitted string was not a supported TikTok username or profile URL. This row is stored only when `skipInvalidInputs` is `false`; no TikTok request is made. |

The Actor always stores `ok`, `not_found`, and `restricted` results. A
`not_found` or `restricted` row includes the requested username, profile URL, and
collection time; account fields are `null`. An `invalid_input` row contains the
redacted submitted string in `username`, sets `url` and all account fields to
`null`, and includes the collection time. These outcomes do not trigger retries
or dedicated warning/error logs.

A blank page, verification challenge, malformed response, rate limit, or HTTP error is retried rather than treated as `not_found`. Failed profile requests are retried up to **3 times**, for a maximum of **4 attempts per profile**. If all attempts fail, the profile is counted as failed in the run log and no result row is written. A completed run can therefore contain fewer rows than the number of unique usernames submitted.

Unrecognized TikTok business status codes are logged once as errors and skipped
without retries or dataset rows. The run continues with the remaining profiles.

Fields and counts depend on what TikTok returns for the account and request location. Some values may be unavailable even when you can see them in a browser. The Actor does not solve verification challenges or access private videos. Avatar URLs may expire.

### How much does it cost to scrape TikTok profiles?

Check the Actor's **Pricing** tab for current rates and review your run limits before starting. On pay-per-event runs, each stored dataset row counts toward dataset-item charges, including `not_found`, `restricted`, and any `invalid_input` rows not omitted with `skipInvalidInputs`. These statuses are results, even when account details are unavailable.

If a result or charge budget is reached, the Actor stops with partial results and a status message. To continue unfinished work, increase the applicable budget and **resurrect the same run**. Keep the same set of normalized target usernames. When `skipInvalidInputs` is `false`, also keep the same invalid input strings. You can reorder inputs or change the run memory without changing their saved task identities.

When cleanup can finish, completed profiles that could not fit within the result budget are saved for recovery. After you increase the budget and resurrect the run, those results are written first without scraping those profiles again. The Actor checks actual dataset records before restoring saved results, including when a previous write had an uncertain outcome. Resurrecting without additional budget stops again with partial results.

### Stopping and resuming a run

Use a **graceful abort** when you intend to resume later. It gives the Actor time to settle active requests, save completed results, and record unfinished work. Apify provides a [30-second cleanup window](https://docs.apify.com/actors/running/runs-and-builds#abort-a-run); cleanup may still be interrupted if it takes longer.

During graceful abort or migration, the Actor stops taking new tasks from the queue. Tasks already taken continue through their normal processing and retries. Completed results are written and their tasks are confirmed while the remaining tasks finish. Completed results awaiting storage are saved for recovery, and each confirmed failed profile is recorded with its completed task. The Actor checks actual dataset rows and recorded task outcomes when resuming. If the platform terminates the process before all active tasks finish, confirmed results and completed tasks remain available for recovery; unfinished tasks may need another attempt. A forced stop can interrupt persistence, so duplicate-free results cannot be guaranteed.

To continue an existing run, use **Actions > Resurrect** in Apify Console. **Re-run** creates a new run rather than continuing the existing one.

After resuming, compare dataset usernames with your input and check the failed count and retry logs. Recovery depends on the saved state and actual dataset records; a forced stop can interrupt persistence.

### FAQ

#### Can I collect videos or follower lists?

This Actor collects profile metadata only. `videoCount` is a count, not a video list.

#### Why are some profiles missing from the dataset?

Invalid inputs are omitted by default; set `skipInvalidInputs` to `false` if you need an `invalid_input` row for each distinct rejected string. For valid targets, check the failed count and retry logs. Temporary upstream errors or verification pages can exhaust retries. Missing rows are different from explicit `not_found` results.

#### Can I check whether a TikTok username is available?

The Actor checks profile responses, not username registration availability. A `not_found` result does not mean that TikTok will let you register that username.

#### Where can I report an issue?

Use the Actor's **Issues** tab when available. Include the affected public username, run URL, and expected behavior. For problems after resuming a run, also mention how the earlier execution was stopped.

### More Actors by AimScrape

Explore other public-data tools from [AimScrape](https://apify.com/aimscrape):

| Actor | Best for |
| --- | --- |
| [Fast YouTube Channel Video Scraper 🚀](https://apify.com/aimscrape/youtube-channel-video-scraper) | Exporting public video metadata from a YouTube channel's Videos tab. |
| [Fast TikTok Profile Scraper 🚀](https://apify.com/aimscrape/tiktok-profile-scraper) | Collecting public TikTok profile details, audience counts, likes, and verification. |
| [Fast YouTube Channel Scraper](https://apify.com/aimscrape/youtube-channel-scraper) | Collecting public YouTube channel metadata, counts, verification, and external links. |
| [Snapchat Profile Scraper](https://apify.com/aimscrape/snapchat-profile-scraper) | Collecting public Snapchat profile metadata, subscriber counts, verification, and Snapcodes. |
| [GitHub Profile Scraper](https://apify.com/aimscrape/github-profile-scraper) | Collecting public GitHub user, organization, and bot profile metadata. |

### Legal & ethical notice

This is an independent, third-party tool. It is not affiliated with, endorsed by, or sponsored by TikTok.

You are responsible for ensuring your use of this Actor and the collected data complies with:

- [TikTok's Terms of Service](https://www.tiktok.com/legal/terms-of-service) applicable to your region.
- Applicable laws and regulations, including privacy and data protection requirements.

Only collect data you are authorized to access, and ensure you have a lawful basis for collecting and using personal data where required by applicable law. Public availability alone does not establish permission to collect or reuse data. Respect users' privacy and do not use the collected data for harassment, spam, or other abusive purposes.

# Changelog

This Actor's version history is a separate document: https://apify.com/aimscrape/tiktok-profile-scraper/changelog.md

# Actor input Schema

## `usernames` (type: `array`):

Add usernames, @usernames, or HTTPS profile URLs from tiktok.com or www.tiktok.com. The Actor validates each string before queueing. Invalid entries do not make network requests and are skipped by default, while valid entries continue.

## `skipInvalidInputs` (type: `boolean`):

Do not store invalid_input results in the Dataset. Invalid entries are still rejected locally without a network request, while valid entries continue normally. Disable this option to store invalid_input rows.

## Actor input object example

```json
{
  "usernames": [
    "https://www.tiktok.com/@tiktok"
  ],
  "skipInvalidInputs": true
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "usernames": [
        "https://www.tiktok.com/@tiktok"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aimscrape/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 = { "usernames": ["https://www.tiktok.com/@tiktok"] }

# Run the Actor and wait for it to finish
run = client.actor("aimscrape/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 '{
  "usernames": [
    "https://www.tiktok.com/@tiktok"
  ]
}' |
apify call aimscrape/tiktok-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,aimscrape/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/3XwmbwgK5TXVgaK3N/builds/5bYef9nbYwgEN3pOT/openapi.json
