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

Scrapes public TikTok profiles and returns account details such as username, display name, user ID, bio, verified status, follower and following counts, likes, videos, and avatar URL. Each profile is read once from its embedded page data, with no login or API key required.

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

## Pricing

from $1.19 / 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

## TikTok Profile Scraper

**Returns:** one row per TikTok profile with username, nickname, followers, following, likes, videos, verified, bio.
**Input:** `{"usernames": ["nasa", "duolingo"], "maxItems": 2}`
**Best for:** creator and lead lists (emails and links from bios), brand and competitor follower tracking, collecting public profile metadata.

```json
{
  "username": "nasa",
  "nickname": "NASA",
  "followers": 2063852,
  "following": 23,
  "likes": 10942352,
  "videos": 56,
  "verified": true,
  "bio": "Making the seemingly impossible, possible.✨"
}
```

This TikTok profile scraper and API returns public profile data without a login.

### What does TikTok Profile Scraper do?

TikTok Profile Scraper collects public profile data for any list of TikTok usernames or profile URLs. It opens each public profile page once, reads the profile data that TikTok embeds in the page, and returns one clean record per account. You get follower, following, likes and video counts together with the bio, verified status, avatar, bio link, language and account creation time. It needs no login and no API key, and it does not collect video lists, comments or private data. Only information visible on a public profile is returned.

The Actor is built for influencer research, brand monitoring, competitor benchmarking, lead lists and audience analytics. Feed it a few handles or thousands, schedule it daily, and compare the counts over time. Each run is small and quick because only one page is fetched per profile, so results arrive in seconds per account.

Typical uses include building a creator database with follower counts and verification status, tracking how follower and like counts of a brand account change from week to week, collecting public profile metadata and privacy flags for a list of handles, and enriching a CRM or spreadsheet with TikTok statistics for known accounts.

### What data can you get?

Every record is a flat JSON object. Fields that TikTok does not expose for an account, such as the bio link on most profiles, are returned as null instead of being dropped, so your columns stay consistent.

| Field | Description |
|---|---|
| `username` | TikTok handle without @ |
| `nickname` | Display name |
| `userId` | Numeric TikTok user ID |
| `bio` | Profile bio text |
| `verified` | Verified badge flag |
| `privateAccount` | Whether the account is private |
| `followers` | Follower count |
| `following` | Accounts followed |
| `likes` | Total likes received |
| `videos` | Public video count |
| `friends` | Mutual follows count |
| `avatarUrl` | Signed avatar image URL (expires) |
| `bioLink` | Link in the bio |
| `language` | Account language code |
| `createdAt` | Account creation time, ISO 8601 |
| `commerceUser` | Commerce account flag |
| `secUid` | TikTok secure user ID |
| `ttSeller` | TikTok Shop seller flag |
| `isOrganization` | Organization account flag |
| `isLive` | Whether a live room was open |
| `likesGiven` | Videos the account has liked |
| `emailsInBio` | Email addresses found in the bio text |
| `hashtagsInBio` | Hashtags found in the bio text |
| `mentionsInBio` | @mentions found in the bio text |
| `sourceUrl` | Profile page the record came from |
| `id` | Stable record ID, equal to userId |
| `scrapedAt` | Collection time |

Total likes are corrected for a known TikTok quirk: for the biggest accounts the raw number overflows a 32-bit integer and turns negative, and the Actor restores the real positive value. The avatar URL is signed by TikTok and expires after some time, so download the image soon if you need to keep it.

### How to use

1. Open the Actor in Apify Console and go to the Input tab.
2. Enter usernames such as `nasa` or `@duolingo` in the Usernames field, or paste profile URLs such as `https://www.tiktok.com/@nba` into Profile URLs. You can use both.
3. Set Max profiles to the number of records you want. The run stops as soon as that many profiles are saved.
4. Keep the default residential proxy. TikTok often blocks datacenter addresses when many profiles are requested.
5. Click Start. When the run finishes, open the Output tab to view the table or download the data as JSON, CSV, Excel or XML.

Usernames that do not exist, or accounts that have been banned or deleted, are skipped and a warning is written to the log. They do not produce empty or error records. If every request is blocked, the run logs a warning and finishes with zero items. Its final status tells you to check the handles and enable the RESIDENTIAL proxy group. A skipped target is unresolved: an empty dataset alone cannot distinguish a missing account from a temporary block.

The Actor spaces request starts by about 125 milliseconds with up to eight concurrent profile requests, and retries blocked requests with growing delays on a fresh proxy session. Duplicate usernames in the input are collapsed, so each account is saved once per run.

### Input

| Field | Type | Description |
|---|---|---|
| `usernames` | array of strings | TikTok usernames, with or without @. Profile URLs are also accepted. |
| `startUrls` | array of URL objects | Profile URLs such as `https://www.tiktok.com/@nba`. Video and hashtag URLs are not supported. |
| `maxItems` | integer | Maximum profiles to save, 1 to 100000. Default 50. |
| `proxyConfiguration` | object | Apify Proxy settings. Default is the residential group. |

Example input:

```json
{
  "usernames": ["nasa", "duolingo", "spotify"],
  "startUrls": [{ "url": "https://www.tiktok.com/@nba" }],
  "maxItems": 4,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

At least one of `usernames` or `startUrls` is required. The lists are combined and deduplicated, with usernames processed first. The maxItems limit is shared across both lists. Missing or blocked targets do not use a result slot, so later targets can still return rows. Defaults do not add targets to API calls; prefilled handles are examples for the Console. An entry that is not a valid username or profile URL stops the run immediately with a clear error message, before any request is made.

### Output

Each profile becomes one item in the dataset. This is a real record from a local run:

```json
{
  "id": "7664638705177150477",
  "username": "nasa",
  "nickname": "NASA",
  "userId": "7664638705177150477",
  "bio": "Making the seemingly impossible, possible.✨",
  "verified": true,
  "privateAccount": false,
  "followers": 2063852,
  "following": 23,
  "likes": 10942352,
  "videos": 56,
  "friends": 17,
  "avatarUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/e5143212a59c09a008bf50f487d54d1f~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=10399&refresh_token=e0d7b1f9&x-expires=1792040400&x-signature=eXi6WabLXcz57vQGHX3tAdZryis%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
  "bioLink": "science.nasa.gov/feature/artemis-ii-preliminary-lunar-science-report",
  "language": "en",
  "createdAt": "2026-07-20T15:55:49.000Z",
  "commerceUser": false,
  "secUid": "MS4wLjABAAAAU9BRVzC8oCaegVnia8IbqWhPb_-dbU7s00Y3wS1_Nx8g5RUaYvyXrpejgjdxTwd6",
  "ttSeller": false,
  "isOrganization": true,
  "isLive": false,
  "likesGiven": 0,
  "emailsInBio": [],
  "hashtagsInBio": [],
  "mentionsInBio": [],
  "sourceUrl": "https://www.tiktok.com/@nasa",
  "scrapedAt": "2026-10-13T05:41:30.259Z"
}
```

The avatarUrl field is a signed image URL from the sampled page and can expire. The dataset has an Overview view that lists the most useful columns, and you can export every field.

### How much does it cost?

The Actor is charged per result, which means per profile saved to the dataset. Profiles that are skipped because they do not exist are not charged. See the Pricing tab of the Actor for the current rate. Under pay-per-event, the publisher pays proxy and compute costs; customers pay the configured result events.

### Use with AI agents (MCP)

You can call this Actor from any MCP-compatible assistant through the Apify MCP server. Add this to your client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/tiktok-profile-scraper"
    }
  }
}
```

Example prompts you can give your assistant:

1. "Get the follower count and verification status of the TikTok accounts nasa, duolingo and spotify."
2. "Scrape the TikTok profiles of nba and netflix and tell me which has more followers."
3. "Collect public profile metadata and privacy flags for nasa and duolingo; report skipped targets as unresolved."

### Integrations and API

You can run the Actor from code, schedule it, or connect it to other tools with Apify integrations such as webhooks, Make, Zapier, Google Sheets and n8n.

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("axiomworks/tiktok-profile-scraper").call(run_input={"usernames": ["nasa"], "maxItems": 1})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["username"], item["followers"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('axiomworks/tiktok-profile-scraper').call({ usernames: ['nasa'], maxItems: 1 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.dir(items);
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~tiktok-profile-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames": ["nasa"], "maxItems": 1}'
```

### FAQ

**Does it need a TikTok account or cookies?** No. It reads only public profile pages and never logs in.

**Can it scrape videos, comments or followers lists?** No. This Actor covers profile data only. Video lists need signed API calls that are outside its scope.

**Why is a field null?** Some accounts have no bio, no bio link or hidden details. New or tiny accounts have sparse data, so only username, nickname, user ID and follower count can be relied on.

**Why do likes look different from the number shown in the app?** The app rounds large numbers, for example 9.9M. The Actor returns the exact count, with the overflow of very large accounts corrected.

**What happens with a private account?** Public profile fields are still returned and privateAccount is true.

**Why did my run return no items?** Either none of the usernames exist, or TikTok blocked the requests. Keep the residential proxy enabled and try again.

**How fresh is the data?** It is read live from the profile page at the moment of the run, and the scrapedAt field records the time.

### Is it legal to scrape TikTok?

The Actor collects only data that is publicly visible without logging in, and it does not bypass any login or CAPTCHA. Public profile data can still be personal data. Depending on where you and the account owners are located, rules such as the GDPR may apply to how you store and use it, so use it for a lawful purpose, keep only what you need, and respect deletion requests. The website's terms of service may also restrict automated access, so review them and take legal advice for your use case. This Actor is an independent tool and is not affiliated with or endorsed by TikTok.

**Tips for reliable runs**

Start with a small maxItems value to confirm the output suits your pipeline, then scale up. Large lists are processed in the order you supply them, so put the most important accounts first. If you schedule the Actor daily to track growth, store the scrapedAt value next to the counts so that you can chart changes over time. When you compare likes across runs, remember that the number is the lifetime total of likes received by the account's videos, so it only moves up unless videos are removed. Follower counts are exact at the time of the request, which means two runs a few minutes apart can differ for fast-growing accounts.

### Feedback

If a field is missing, a profile that should work fails, or you want another data point added, open an issue from the Actor page in Apify Console. Reports that include the username and the run link are the easiest to reproduce and fix.

# Actor input Schema

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

Public TikTok handles with or without @, e.g. \["nasa","@duolingo"], or profile URLs, e.g. \["https://www.tiktok.com/@nasa"]. Supply usernames, startUrls, or both; no targets are added automatically. Duplicates are merged. Missing or blocked profiles are skipped, so zero rows does not prove an account is absent.

## `startUrls` (type: `array`):

Public TikTok profile URLs as URL objects, e.g. \[{"url":"https://www.tiktok.com/@nasa"}]. Combined with usernames under the same maxItems limit. Use /@handle profile pages; video and hashtag data are not collected. For plain URL strings, use usernames instead.

## `maxItems` (type: `integer`):

Maximum profile rows saved across usernames and startUrls combined, 1-100000, default 50. Example: 3 saves up to three distinct profiles in input order. Missing and blocked profiles do not count; later targets are tried until the limit or available targets are exhausted.

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

Proxy settings for TikTok requests, e.g. {"useApifyProxy":true,"apifyProxyGroups":\["RESIDENTIAL"]}. Default uses Apify residential proxy. Blocked requests retry with backoff on fresh sessions. If no rows are returned, check the handles, enable RESIDENTIAL, and retry.

## Actor input object example

```json
{
  "usernames": [
    "nasa",
    "duolingo",
    "spotify"
  ],
  "startUrls": [],
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (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": [
        "nasa",
        "duolingo",
        "spotify"
    ],
    "maxItems": 3,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/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": [
        "nasa",
        "duolingo",
        "spotify",
    ],
    "maxItems": 3,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/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": [
    "nasa",
    "duolingo",
    "spotify"
  ],
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call axiomworks/tiktok-profile-scraper --silent --output-dataset

```

## MCP server setup

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