# TikTok Profile Scraper | Followers, Following & Bio Emails (`corvuslab/tiktok-profile-scraper`) Actor

Scrape TikTok profiles with follower, following, heart and video counts, bio text, bio links and extracted emails. Pull full follower and following lists, and track follower growth between runs.

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

## Pricing

from $0.50 / 1,000 tiktok profiles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

Turn any TikTok account into structured data — follower and heart counts, bio text, bio links, emails pulled out of the bio, and the full list of who follows them. Paste handles or profile URLs, press Start, and get JSON, CSV or Excel back. No proxy to configure.

### What does TikTok Profile Scraper do?

It reads TikTok accounts and returns them as flat, joinable records.

Give it a handle (`@tiktok`) or a profile URL and you get that account's metadata: display name, bio, bio link, verification, account age, follower count, following count, total likes received, and how many videos it has posted. Turn on **Scrape followers** and it also walks that account's follower list, returning one full record per follower — with *their* stats and bio, not just a username. **Scrape following** does the same for the accounts the profile follows.

That second part is what makes this more than a lookup tool. A follower record carries the same fields as a profile record, so a single run can hand you an entire audience as a spreadsheet: 5,000 accounts with their follower counts, bios and contact details, each tagged with whose list it came from.

Emails and links are extracted from every bio automatically into `extractedEmails`, `extractedPhones`, `extractedUrls` and `socialProfiles`, so creator outreach lists come out ready to use instead of needing a second pass over the bio text.

### What data can you extract from a TikTok profile?

Every record — whether it is an account you asked for or one of its followers — carries the same fields:

| Field | Description |
|---|---|
| `uniqueId` | The @handle, without the @ |
| `nickname` | Display name |
| `id` | TikTok's internal user ID, stable across handle changes |
| `secUid` | TikTok's secondary user ID — the identifier its own endpoints accept, so you can re-query this account yourself |
| `url` | Link to the profile |
| `signature` | Bio text |
| `bioLink` | The clickable link in the bio |
| `verified` | Blue-check status |
| `privateAccount` | Whether the account is private |
| `followerCount` | Followers |
| `followingCount` | Accounts this profile follows |
| `heartCount` | Total likes received across all videos |
| `videoCount` | Public videos posted |
| `diggCount` | Likes this account has given out |
| `friendCount` | Mutual follows |
| `createTime` / `createTimeISO` | When the account was created |
| `avatar` / `avatarThumb` | Profile picture, full size and thumbnail |
| `commerceUser` / `ttSeller` | Business account and TikTok Shop seller flags |
| `isOrganization` | Official organization or brand account |
| `language` | The account's declared language, e.g. `en` |
| `isLive` | The account was live-streaming at the moment it was scraped |
| `nicknameModifiedAt` / `handleModifiedAt` | When the display name and @handle were last changed — a rebrand signal |
| `extractedEmails` | Emails found in the bio |
| `extractedPhones` | Phone numbers found in the bio |
| `extractedUrls` | Links found in the bio and bio link |
| `socialProfiles` | Instagram, YouTube, LinkedIn and other handles found in the bio |
| `dataType` | `profile`, `follower` or `following` |
| `relationTo` | For follower/following records: whose list this account came from |
| `changeType` | In monitoring mode: `NEW`, `UPDATED`, `UNCHANGED` or `EXPIRED` |

Six of these come only from the profile page itself: `isOrganization`, `language`, `isLive`, `nicknameModifiedAt`, `handleModifiedAt` and `commerceUser`. TikTok does not report them on a follower or following list, so those records carry `null` rather than a `false` that would read as a checked answer. Everything else — including `secUid` — is on every record. To resolve them for an account you found in a follower list, feed that handle back in as a profile.

`heartCount` is the field most worth understanding: it is lifetime likes across every video the account has posted, which is a far better measure of whether an audience actually engages than follower count on its own. Divide it by `videoCount` and you have an average-likes-per-video figure you can rank a list of creators by.

### Key features

- **Followers and following in one actor.** Most tools split these into separate listings. Here they are two checkboxes on the same run.
- **Full records, not usernames.** Each follower arrives with their own follower count, bio, verification and engagement totals, so you can filter an audience without a second scrape.
- **Emails and links pulled out of bios** into their own fields, ready for outreach.
- **Lead filters** — minimum and maximum follower counts, verified-only, and "must have an email in the bio" — applied while the run is in progress.
- **Growth monitoring.** Run it on a schedule and get only the accounts whose numbers moved, each tagged with what changed.
- **Unfollow detection.** Track a follower list over time and accounts that disappear come back as `EXPIRED` records.
- **Alerts** to Telegram, Slack, Discord or any webhook.
- **No proxy required.** Leave the proxy setting alone and the run works.
- **Custom map function** to reshape records before they are saved.
- **Clean exports** — JSON, CSV, Excel, XML, or straight into your own systems via the API.

### How to scrape a TikTok profile

1. Open the actor. **Profile URLs** comes prefilled with an example, so you can press **Start** immediately and see real output.
2. Replace it with the accounts you want. Full URLs (`https://www.tiktok.com/@khaby.lame`) and bare handles (`khaby.lame`, `@khaby.lame`) both work, one per line.
3. To collect audiences, turn on **Scrape followers** and set **Followers per profile**. Start small — 30 or 60 — to see the shape of the output before you scale up to the 5,000 maximum.
4. Optionally set **Minimum followers** or **Require contact details** to keep only the accounts worth acting on.
5. Set **Max results** to cap the whole run, then press **Start**.

Leave **Proxy configuration** switched off. This actor does not need one, and turning it on only slows the run down.

### Input

```json
{
  "profileUrls": [
    "https://www.tiktok.com/@khaby.lame",
    "@tiktok"
  ],
  "includeFollowers": true,
  "followersPerProfile": 500,
  "minFollowers": 1000,
  "requireContact": "email",
  "maxResults": 1000
}
```

That run reads both accounts, walks up to 500 followers of each, and keeps only followers with at least 1,000 followers of their own and an email address in their bio — a creator-outreach list built in one pass.

The accounts you name yourself are always returned in full. Filters apply only to follower and following records, so a strict filter can never leave you with an empty dataset and no idea why.

Other inputs worth knowing: **Scrape following** and **Following per profile** for the outbound list, **Verified accounts only**, **Start URLs** if you prefer one mixed list of links, and **Compact records** to trim every record down to the core fields for AI agents and MCP clients.

### Output

One record per account. This is a real profile record:

```json
{
  "id": "127905465618821121",
  "secUid": "MS4wLjABAAAAv3zolJLlWp-WbKXqSZwVSflDdwcbjPADRG-dhb68k30",
  "uniqueId": "khaby.lame",
  "nickname": "Khabane lame",
  "url": "https://www.tiktok.com/@khaby.lame",
  "signature": "Se vuoi ridere sei nel posto giusto If u wanna laugh u r in the right place",
  "bioLink": null,
  "verified": true,
  "privateAccount": false,
  "createTime": 1470866554,
  "createTimeISO": "2016-08-10T22:02:34+00:00",
  "followerCount": 162810090,
  "followingCount": 81,
  "heartCount": 2672524185,
  "videoCount": 1352,
  "diggCount": 0,
  "friendCount": 77,
  "commerceUser": false,
  "ttSeller": false,
  "isOrganization": false,
  "language": "it",
  "isLive": false,
  "nicknameModifiedAt": "2021-03-14T09:12:05+00:00",
  "handleModifiedAt": null,
  "dataType": "profile",
  "source": "tiktok.com",
  "scrapedAt": "2026-09-13T15:25:02.099912+00:00"
}
```

A follower record looks the same, plus three fields that say where it came from:

```json
{
  "id": "7502842562769847304",
  "uniqueId": "creator_example",
  "nickname": "Creator Example",
  "url": "https://www.tiktok.com/@creator_example",
  "signature": "collabs: hello@example.com",
  "followerCount": 14620,
  "heartCount": 656000,
  "videoCount": 1196,
  "extractedEmails": ["hello@example.com"],
  "isOrganization": null,
  "language": null,
  "isLive": null,
  "dataType": "follower",
  "relationTo": "khaby.lame",
  "relationToId": "127905465618821121",
  "relationToUrl": "https://www.tiktok.com/@khaby.lame"
}
```

Because `relationTo` is on every row, you can scrape the followers of several accounts in one run and still separate the audiences afterwards — or intersect them to find the people who follow all of your competitors.

### How can you monitor a TikTok profile over time?

Turn on **Incremental mode**. The actor remembers what it saw last time and compares each run against it.

Records come back tagged with a `changeType`: `NEW` for accounts it has not seen before, `UPDATED` for ones whose follower, likes or video counts moved, and `UNCHANGED` for the rest — which are hidden by default, so a scheduled run returns only movement.

Turn on **Report accounts that disappeared** and you also get `EXPIRED` records: an account that was in a follower list last week and is not there now. That is an unfollow, and it is the signal that is hardest to get any other way.

Give related runs the same **State key** to keep them on one shared history, or leave it empty and one is derived from your input automatically.

### What alerts and notifications are available?

Fill in any of the notification fields and matching records are pushed out as they are found:

- **Telegram** — a bot token from @BotFather plus your chat or channel ID.
- **Slack** — an incoming-webhook URL.
- **Discord** — an incoming-webhook URL.
- **Any webhook** — an HTTPS endpoint that receives a JSON POST, which is how you wire this into n8n, Make or Zapier.

Every channel is off unless you fill it in, and a failing notification never breaks the run. Combined with monitoring mode and a schedule, this gives you a follower-growth alert without writing any code.

### What can you do with TikTok profile data?

- **Influencer discovery and vetting** — pull a shortlist of creators and rank them on real engagement rather than follower count alone.
- **Creator outreach lists** — scrape the followers of an account in your niche, filter to those with an email in their bio, and export straight to your CRM.
- **Audience overlap analysis** — scrape the followers of several accounts and find the people who follow all of them.
- **Competitor tracking** — watch a rival's follower count, posting volume and bio link on a schedule, and get alerted when any of it changes.
- **Campaign measurement** — snapshot a creator's numbers before and after a campaign and measure what actually moved.
- **Lead generation** — business accounts and TikTok Shop sellers are flagged, and their contact details are extracted for you.
- **Academic and market research** — build a reproducible dataset of accounts in a category, with timestamps on every record.

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

Pricing is pay-per-event and shown live on this actor's Store page. There are two kinds of record: the accounts you name, and the follower or following records collected underneath them. Each is priced for its own lane, so a run that only looks up a handful of profiles does not pay audience-scale prices.

The practical lever is **Max results**, which caps the total number of records a run can produce, and **Followers per profile**, which stops one huge account from consuming the whole budget. Set both before scaling a job up. You can also set a maximum spend per run in the actor's run options, and the actor stops cleanly when it is reached rather than overshooting.

Leaving the proxy off is the other saving — it is off by default, and it should stay that way unless you have a specific reason.

### Integrations and export options

Results land in a standard Apify dataset, which you can download as **JSON, CSV, Excel, XML or JSONL**, or read through the API. From there the usual integrations apply: Zapier, Make, n8n, Airbyte, Google Sheets, and the webhook field above for anything else.

For AI workflows, **Compact records** trims each record to the core fields — handle, name, URL, follower count, type and change type — which keeps token counts down when the output is being fed to a model or served through an MCP client.

### How do you use the TikTok Profile Scraper API?

Every Apify actor is an API endpoint. Start a run and wait for its results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/corvuslab~tiktok-profile-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "profileUrls": ["@khaby.lame"],
    "includeFollowers": true,
    "followersPerProfile": 100,
    "maxResults": 101
  }'
```

The response is the dataset as a JSON array. Official clients are available for Python and JavaScript, and the actor can be triggered on a schedule from the Console without any code at all.

### FAQ

**Can I get the full follower list of a large account?**
You can collect up to 5,000 followers per account per run, newest-follower-first — a verified 5,000 out of 5,000 on an account with 95 million followers. TikTok throttles a walk that deep; the run rides that out rather than stopping early, and in the rare case a list is still cut short it says so explicitly in the log instead of pretending the account has fewer followers than it does. For accounts with millions of followers, 5,000 is a recent, complete-from-the-top sample rather than the whole list, and scheduled runs extend it over time.

**Why do some accounts return no followers?**
Private accounts do not expose their lists, and TikTok withholds them for some accounts regardless of size. The run logs which account it was and carries on with the rest.

**Does this actor scrape a creator's videos?**
No, deliberately. This one sells the account: metadata, audiences and contacts — `videoCount` and `heartCount` tell you how much a creator posts and how much those posts are liked, without pulling the posts themselves. If you need the videos, scrape the account here first and use the handles it returns as input to a video-level actor.

**Do I need a proxy?**
No. Leave the proxy setting off — both things this actor reads are served without one.

**What is the difference between `followerCount` and `heartCount`?**
`followerCount` is how many accounts follow the profile. `heartCount` is the total number of likes all of its videos have received, ever. A high follower count with a low heart count is the classic signature of an audience that does not engage.

**Are the emails in `extractedEmails` verified?**
They are taken verbatim from what the account put in its own bio, so they are self-published and current as of the scrape, but they are not deliverability-checked. Run them through your own verification before a large send.

**Can I scrape accounts by keyword instead of naming them?**
Not in this actor — it works from accounts you name. Keyword-based creator discovery is a separate job with a different cost profile.

**Is scraping TikTok profiles legal?**
This actor reads publicly visible profile pages — what anyone sees without logging in. Public data collection is broadly lawful in most jurisdictions, but profiles describe real people, so if you store or publish the results, handle them in line with GDPR, CCPA and TikTok's own terms. Take legal advice if you are unsure how that applies to your use.

**Can I reshape the output?**
Yes — **Custom map function** applies a JavaScript function to every record before it is saved, so you can rename fields, drop the ones you do not need, or compute your own.

### Related TikTok scrapers

- **TikTok Comments Scraper** — pulls the comments and replies under any TikTok video, each with its author, like count and reply thread. It is the natural next step after this actor: profile data tells you who an audience *is*, and comment data tells you what it *says*. Both use the same field conventions, so `uniqueId` joins one dataset straight onto the other.

***

**Keywords:** TikTok profile scraper · scrape TikTok followers · TikTok follower list export · TikTok user data API · TikTok bio email extractor · TikTok influencer discovery · TikTok following scraper · export TikTok profiles CSV · TikTok creator lead generation · TikTok follower growth tracking · TikTok account monitoring · TikTok audience analysis · bulk TikTok profile lookup · TikTok unfollow tracker · TikTok engagement metrics · no-code TikTok scraper

# Actor input Schema

## `profileUrls` (type: `array`):

TikTok profiles to scrape. Full URLs (https://www.tiktok.com/@tiktok) or bare handles (tiktok, @khaby.lame) both work.

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

Any mix of TikTok URLs. Profile URLs are scraped; anything else is skipped with a warning.

## `includeFollowers` (type: `boolean`):

Also collect the accounts that follow each profile, as one record per follower with their own stats and bio.

## `followersPerProfile` (type: `integer`):

How many followers to collect per profile. TikTok serves these 30 at a time, newest follower first, and throttles a deep walk — the run rides that out and keeps going. If it is ever cut short anyway, the log says so and you get what was collected.

## `includeFollowing` (type: `boolean`):

Also collect the accounts each profile follows — the shorter, higher-signal list for mapping who a creator pays attention to.

## `followingPerProfile` (type: `integer`):

How many followed accounts to collect per profile. Same 30-at-a-time paging and the same behaviour at depth as followers.

## `minFollowers` (type: `integer`):

Drop follower/following records below this follower count. Leave empty for no minimum.

## `maxFollowers` (type: `integer`):

Drop follower/following records above this follower count — the way to filter for micro-influencers. Leave empty for no maximum.

## `verifiedOnly` (type: `boolean`):

Keep only blue-check accounts in the follower/following lists.

## `requireContact` (type: `string`):

Keep only follower/following records whose bio contains contact details. Emails and links are extracted from every bio either way.

## `maxResults` (type: `integer`):

Maximum number of records to return in total, profiles and followers combined. Set 0 for unlimited.

## `incrementalMode` (type: `boolean`):

Track state between runs and emit only profiles whose follower, heart or video counts changed since last time, each tagged with a changeType. New and unfollowed accounts show up as NEW and EXPIRED.

## `stateKey` (type: `string`):

Stable name for the tracked set of profiles. Leave empty to derive one automatically from your input URLs.

## `emitUnchanged` (type: `boolean`):

Also emit records that have not changed since the previous run.

## `emitExpired` (type: `boolean`):

Emit an EXPIRED record for anything present last run but missing now — an unfollow when you are tracking a follower list, a deleted or renamed account when you are tracking profiles.

## `telegramToken` (type: `string`):

Bot token from @BotFather.

## `telegramChatId` (type: `string`):

Chat or channel ID, e.g. "-100123456789" or "@yourchannel".

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL.

## `discordWebhookUrl` (type: `string`):

Discord incoming-webhook URL.

## `webhookUrl` (type: `string`):

Any HTTPS endpoint. Receives a JSON POST with the matched records — works with n8n, Make, and Zapier.

## `webhookHeaders` (type: `object`):

Extra headers for the webhook request, e.g. {"Authorization": "Bearer xyz"}.

## `notificationLimit` (type: `integer`):

How many records to include in each notification message.

## `compact` (type: `boolean`):

Emit only the core fields (id, uniqueId, nickname, url, followerCount, dataType, changeType). Ideal for AI agents and MCP clients.

## `excludeEmptyFields` (type: `boolean`):

Remove null, empty-string, and empty-array fields from each record.

## `customMapFunction` (type: `string`):

JavaScript function applied to every record before it is saved, e.g. (object) => { return {...object} }. Use it to reshape or trim output, not to filter.

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up on it.

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

Not needed. Both surfaces this actor uses answer from Apify's own IPs, so leave this off unless you have a reason to route the run through a specific country.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.tiktok.com/@tiktok",
    "https://www.tiktok.com/@khaby.lame",
    "@bellapoarch"
  ],
  "includeFollowers": false,
  "followersPerProfile": 30,
  "includeFollowing": false,
  "followingPerProfile": 30,
  "verifiedOnly": false,
  "requireContact": "off",
  "maxResults": 100,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "notificationLimit": 5,
  "compact": false,
  "excludeEmptyFields": false,
  "customMapFunction": "(object) => { return {...object} }",
  "maxRequestRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `allItems` (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 = {
    "profileUrls": [
        "https://www.tiktok.com/@tiktok",
        "https://www.tiktok.com/@khaby.lame",
        "@bellapoarch"
    ],
    "customMapFunction": (object) => { return {...object} }
};

// Run the Actor and wait for it to finish
const run = await client.actor("corvuslab/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 = {
    "profileUrls": [
        "https://www.tiktok.com/@tiktok",
        "https://www.tiktok.com/@khaby.lame",
        "@bellapoarch",
    ],
    "customMapFunction": "(object) => { return {...object} }",
}

# Run the Actor and wait for it to finish
run = client.actor("corvuslab/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 '{
  "profileUrls": [
    "https://www.tiktok.com/@tiktok",
    "https://www.tiktok.com/@khaby.lame",
    "@bellapoarch"
  ],
  "customMapFunction": "(object) => { return {...object} }"
}' |
apify call corvuslab/tiktok-profile-scraper --silent --output-dataset

```

## MCP server setup

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