# TikTok Profile Scraper — Emails, Followers & Commenters (`afanasenko/tiktok-profile-scraper`) Actor

Scrape TikTok profile data at scale — followers and following lists, video commenters, and username enrichment. Every profile returns emails, bio links, follower and like counts, and video stats. No login needed. Export to CSV, JSON or Excel, or run via API.

- **URL**: https://apify.com/afanasenko/tiktok-profile-scraper.md
- **Developed by:** [Andrey Afanasenko](https://apify.com/afanasenko) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 241 total users, 27 monthly users, 99.8% runs succeeded, 6 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$2.00 / 1,000 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## TikTok Profile Scraper

[![Apify Actor](https://apify.com/actor-badge?actor=afanasenko/tiktok-profile-scraper)](https://apify.com/afanasenko/tiktok-profile-scraper)

> **Discover, enrich and filter TikTok profiles at scale for influencer discovery and lead generation. Three modes — scrape followers/following of target accounts, enrich a username list, discover engaged commenters. 13 filters plus emails and bio links parsed from every profile.**

TikTok's official Research API requires institutional approval and limits the data you can pull. This actor reads any public TikTok profile and returns 20+ enrichment columns per row, including bio, business category, language, engagement rate, and email parsed from the bio.

### 🎯 What it does

You give the actor one or more TikTok account handles plus a mode, and it returns one row per discovered profile, fully enriched. **Pick the Operation Mode first** — each mode reads its own input fields, and inputs typed into another mode's section are ignored.

| Mode | Input | What it returns |
|---|---|---|
| **1. Followers / Following** | 1–3 target accounts | Followers and/or following of each target, enriched. Public accounts with visible lists only — private targets and hidden lists return nothing. Very long lists may be read in part; the run says how many of how many it read. |
| **2. Specific list** | A list of TikTok usernames you already have | Each username enriched (no follower scraping — straight enrichment). |
| **3. Engaged Audience** | 1–3 target accounts | Unique commenters from each target's recent posts, enriched and ranked by how often they engaged. Surfaces real, active people in the audience — high-intent leads. |

For every profile that comes back you get:

- **Identity** — Account URL, Full Name, Profile Picture, Verified flag.
- **Audience** — Followers Count, Following Count, Likes Count, Videos Count.
- **Engagement** — Median Views (recent), Most Viewed Video Plays, Avg. Shares (Recent), ER (incl. shares) (%) — formatted to two decimals.
- **Recency** — Last Post Date as ISO timestamp.
- **Bio + classification** — Biography, Profile Language (ISO 639-1), Category (TikTok business taxonomy).
- **Optional contacts** — Email parsed from bio, Website (bio link).
- **Optional post sample** — captions of the N most-recent or most-popular videos.

Then the actor applies **your filters** (followers band, engagement floor, language, category, verification, last-post recency, keyword match) so only profiles matching your target persona end up in the dataset.

### 📦 Output sample

Every analyzed profile is pushed to the dataset as one item. Here's a real row:

```json
{
  "Account": "https://tiktok.com/@therock",
  "Source": "Direct Input",
  "Profile Picture": "https://p16-sign.tiktokcdn-us.com/%E2%80%A6/profile.jpeg",
  "Full Name": "Dwayne Johnson",
  "Followers Count": 78400000,
  "Following Count": 657,
  "Likes Count": 467000000,
  "Videos Count": 612,
  "Median Views": 4200000,
  "Most Viewed Video Plays": 38000000,
  "Avg. Shares (Recent)": 12500,
  "ER (incl. shares) (%)": "1.85",
  "Last Post Date": "2026-04-01T14:00:00.000Z",
  "Biography": "🎬 Actor & Producer | The Smashing Machine — in theaters now",
  "Profile Language": "en",
  "Verified": "Yes",
  "Category": "Public Figure",
  "Email": "press@example.com",
  "Website": "https://www.example.com/"
}
```

Profiles with no posts return `"No Content"` for engagement-derived columns (Median Views, ER, Last Post Date, Profile Language, Avg. Shares, Most Viewed Video Plays). Missing optional values such as Email return `"N/A"` rather than `null`, so every base column is always present and downstream code can rely on a stable shape.

`Source` tells you how each profile entered the results — `Follower of <target>` / `Following of <target>` in Mode 1, `Direct Input` in Mode 2, `Commenter on <target>` in Mode 3. When you run several target accounts at once, this is what keeps each row traceable back to the account it came from.

Mode 3 rows carry two extra columns:

| Column | What it tells you |
|---|---|
| `Comments Left` | How many comments this account left across the target posts that were read. Someone who commented five times ranks above someone who commented once. |
| `Posts Engaged` | How many different target posts they commented on — separates steady engagement from a burst of replies under one post. |

Both count what the run actually read: scanning stops once the profile limit is reached, so treat them as a floor rather than a lifetime total. An account that comments on several of your target accounts accumulates across all of them, and `Source` lists each one.

Results are written to the dataset in batches, most engaged first within each batch. For a strict ranking across the whole run, sort the exported dataset by `Comments Left`.

### ⚡ Quick start

1. **Paste this input** into the Input tab in the Apify Console (the `operationMode` line picks the mode — set it first when building your own input).
2. **Click Run** — the first run takes 30–60 seconds.
3. **Open the Output tab** — preview the dataset, export as JSON / CSV / Excel.

```json
{
  "operationMode": "analyzeSpecificAccounts",
  "specificUsernamesList": ["therock", "khaby.lame", "bella.poarch"],
  "maxCountList": 5,
  "extractEmail": true
}
```

That's 3 well-known creators capped at 5 profiles — about $0.01.

### 🎯 Example tasks

Ready-to-run examples — each opens a pre-configured task you can run in one click (no setup):

- **[Scrape TikTok profiles by username](https://apify.com/afanasenko/tiktok-profile-scraper/examples/scrape-tiktok-profiles-by-username)** — Enter TikTok usernames and export full profiles — followers, bio, category, verified status, email and website link — as clean structured data.
- **[Find TikTok influencer emails & contact info](https://apify.com/afanasenko/tiktok-profile-scraper/examples/find-tiktok-influencer-emails)** — Pull contact details for any TikTok creator — email from bio, website link, follower count and category — ready for outreach.
- **[Analyze TikTok engagement rate & metrics](https://apify.com/afanasenko/tiktok-profile-scraper/examples/analyze-tiktok-engagement-metrics)** — Measure any TikTok creator's engagement — median views, average shares, likes and recent post performance — in one structured export.

### 🧭 When to use it

1. **Influencer outreach** — discover creators in a niche by category + language + follower band, then export emails for outreach.
2. **Lead generation from commenters (Mode 3)** — surfaces real people actively engaging with a brand or competitor — high-intent warm leads.
3. **Competitor benchmarking (Mode 2)** — paste a known list of competitor accounts and benchmark engagement, posting cadence, and audience size in one run.
4. **Audience expansion (Mode 1)** — from one target account, expand into followers and follow-graphs to build a top-of-funnel list.
5. **Verified-only campaigns** — `mustBeVerified: true` plus a follower minimum gives a celebrity / brand shortlist for sponsorship deals.

### 🛠 Input

The input form is grouped into four sections:

| Section | Purpose |
|---|---|
| **🎯 Mode 1 / 2 / 3** | Pick a mode and provide its target inputs (target accounts or username list). |
| **⚙️ Data Extraction Options** | Which enrichments to emit (email, website, post captions). |
| **🔬 Advanced Filtering (Optional)** | 11 filters that drop non-matching profiles before they're billed. |
| **▶️ Run & Storage Options** | Resume from checkpoint, budget cap. |

**Highlights:**

- **`operationMode`** — `analyzeFollowersFollowing`, `analyzeSpecificAccounts`, or `analyzeEngagedAudience`. Set this first — it decides which username field the run reads.
- **`maxCount` / `maxCountList` / `maxEngagedProfiles`** — hard cost ceiling per mode (each profile = one $0.002 event).
- **`maxBudgetUsd`** — alternative cost ceiling expressed in USD. The run stops when the budget is about to be exceeded.
- **`minFollowers` / `maxFollowers`** — most-used filter (e.g. 1,000–10,000 for nano-influencers).
- **`minEngagementRatio`** — typical B2B floor: 1–3 %. Highly engaged niches see 5–10 %.
- **`profileLanguages`** — restrict to one of 29 detected languages.
- **`postExtractionMode`** — `recent` or `popular` to fetch up to 20 caption strings as `Post 1..Post N`.

### 💰 How much will scraping TikTok cost?

Pay-per-event with **one single primary event**:

| Event | Price | Triggered |
|---|---|---|
| **Profile Analyzed** | **$0.002** | Once per profile that's successfully retrieved (live or from cache) and analyzed, regardless of whether it passes your filters. |

Per-profile billing — your per-mode cap translates directly to maximum spend.

| Cap | Plan | Approx cost |
|---|---|---|
| 5 | Free | $0.01 |
| 100 | Free | $0.20 (free-plan ceiling) |
| 500 | Paid | $1.00 |
| 1,000 | Paid | $2.00 |
| 10,000 | Paid | $20.00 |

**Cap costs hard with Apify's "Maximum cost per run"** Run option in the right panel. Tighter filters mean more profiles are retrieved before you find matches — be conservative with the per-mode cap when stacking many filters.

### 🆓 Free vs paid plan

| | Free plan | Paid plan |
|---|---|---|
| Profiles per run | up to 100 | unlimited |
| Runs per calendar month | 15 (resets on the 1st, UTC) | unlimited |
| Target accounts (Mode 1 & 3) | up to 3 | unlimited |
| Default budget cap | $5 | $1,000 (configurable) |
| All filters (followers, language, ER, category, …) | ✅ | ✅ |
| Resume from checkpoint | ✅ | ✅ |
| Single PPE event ($0.002 / profile) | counts toward free-tier credit | yes |

Every profile the free plan analyzes comes back complete — nothing inside a delivered row is
masked. When the free caps trim your input (a long username list, or more than 3 target
accounts), the trimmed usernames are **previewed at the end of your dataset** (`Row Status =
'withheld_free_plan'`, never charged) so you can see exactly what a paid plan would analyze. A
free account that has used its 15 monthly runs gets $0 runs with an explanation until the 1st.

### 🧪 Filter recipes

**Nano-influencer outreach (B2C beauty / fitness):**

```json
{
  "operationMode": "analyzeFollowersFollowing",
  "targetUsernames": ["sephora"],
  "analyzeFollowers": true,
  "maxCount": 500,
  "minFollowers": 1000,
  "maxFollowers": 10000,
  "minEngagementRatio": 3,
  "lastPostDays": 30,
  "extractEmail": true,
  "filterForInfluencers": true
}
```

**Active English-speaking creators (Mode 2 enrichment of a known list):**

```json
{
  "operationMode": "analyzeSpecificAccounts",
  "specificUsernamesList": ["…your 50 usernames…"],
  "maxCountList": 50,
  "profileLanguages": "English",
  "lastPostDays": 14,
  "minMedianViews": 10000,
  "extractEmail": true
}
```

**B2B partnership shortlist via engaged commenters (Mode 3):**

```json
{
  "operationMode": "analyzeEngagedAudience",
  "engagedAudienceTargetUsernames": ["competitor-handle"],
  "maxEngagedProfiles": 200,
  "filterForInfluencers": true,
  "accountType": "business",
  "minEngagementRatio": 2,
  "extractEmail": true
}
```

### 🔁 Resume / checkpoint

Long runs can be interrupted (timeout, manual stop, abort). The actor writes a checkpoint to its key-value store after every batch and persists the per-account list to a checkpoint dataset. To resume, run the actor again with **`clearSavedData`** unchecked — already-processed profiles are not re-fetched and not re-billed.

### 📡 Live status & storage records

While the run is in progress, the actor exposes:

| Storage key | What it holds |
|---|---|
| `RUN_SUMMARY` | Aggregate run statistics — counts, plan, pricing, timings, success rate. |
| `TOTAL_ACCOUNTS_TO_PROCESS` | Total candidate count — written once after discovery, before enrichment. Useful for ETA dashboards. |
| `checkpoint-kvs-tiktok-limited` | Last batch index, spend so far, budget-exhausted flag. |
| `checkpoint-dataset-tiktok-limited` | One row per processed username — used for resume. |

These are stable, machine-readable surfaces — pull them via the Apify API for dashboards or post-processing.

### 🤖 Programmatic API

**REST — start a run:**

```bash
curl -X POST "https://api.apify.com/v2/acts/afanasenko~tiktok-profile-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"operationMode":"analyzeSpecificAccounts","specificUsernamesList":["therock","khaby.lame"],"maxCountList":2,"extractEmail":true}'
```

**MCP / agentic clients (Claude Desktop, Cursor, ChatGPT, LangGraph, OpenAI Agents SDK, …):**

The actor is exposed as a tool through Apify's MCP server at `mcp.apify.com`. Once your MCP-enabled client is connected to your Apify token, an LLM can search, inspect input + output schemas, and run the actor with natural-language instructions like *"find 50 verified TikTok fitness creators with 10–50k followers and an engagement rate above 3 %"*.

### 💡 Tips & Best Practices

#### Getting maximum results

- **Start with Mode 2 to validate filter shape** — paste 5 known accounts, check the output, then switch to Mode 1 or Mode 3 for discovery.
- **Mode 3 (engaged audience) gives higher-intent leads** than Mode 1's full follower list — commenters have already engaged with the target's content.
- **Layer filters in order of impact**: follower band → engagement floor → language → category. Each filter narrows the candidate pool before paid events fire.

#### Cost optimization

- **At $0.002 per profile, this is the cheapest of all our actors** — use a higher per-mode cap (500–1,000) for richer data without breaking the bank.
- **Use Apify's Maximum cost per run** Run option for a hard ceiling on top of `maxBudgetUsd`.
- **Disable optional extractions** when you don't need them: `extractEmail: false`, `extractWebsiteUrl: false`, `postExtractionMode: "none"` — leaner output, same per-profile cost.

#### Performance

- Throughput is roughly 200–400 profiles/min depending on enrichments. A 100-profile run finishes in ~30 seconds; a 1,000-profile run in 4–6 minutes.
- **Resume is automatic** via `clearSavedData: false` — use it instead of restarting from scratch on interrupted runs.
- Mode 3 (engaged audience) is the slowest mode because it reads recent posts of each target before collecting commenters.

#### Data quality

- **`Profile Language` returns "N/A"** when bio + posts are too short for reliable detection — common on dormant accounts.
- **`"No Content"` rows** indicate the profile has no public videos. Account, Followers Count, Biography, Verified, and Category are still populated.
- **Trust verified accounts** (`Verified: "Yes"`) over follower count alone — TikTok's verification gate filters most bot accounts.

### ❓ FAQ

**Is it legal to scrape TikTok?**
Scraping public data is legal in most jurisdictions — see § Is it legal to scrape TikTok? below. The actor only reads what's already public on the profile page; private user data is never touched.

**Can I get banned for using this actor?**
No. The actor is the one making requests, not your account. Apify proxies rotate IPs upstream so individual users aren't fingerprinted.

**How is engagement rate calculated?**
`((avg likes + avg comments + avg shares) / followers) * 100` over the user's ~35 most recent videos. The recent-window average is more representative than lifetime totals — engagement on TikTok decays steeply with account age.

**What does "No Content" mean in my output?**
The profile has no public videos, so view-, share- and engagement-derived metrics can't be computed. The Account, Followers Count, Biography, Verified, and Category columns are still populated.

**Why is `Profile Language` showing "N/A"?**
Bio and post text combined were too short or too ambiguous (only emojis or hashtags) for reliable language detection. Active accounts with regular captions are detected reliably across 29 languages.

**Can I resume an interrupted run?**
Yes — uncheck **Start a Fresh Run** (set `clearSavedData: false`). The next run continues from the last successfully processed batch, and processed profiles are not re-billed.

**Is the data live?**
Every profile retrieved triggers a live request — there's no cross-run cache shared between users. Within a single resume sequence (`clearSavedData: false`), already-processed profiles are reused from the run's own checkpoint.

**How many usernames can I pass to Mode 2?**
Free plan caps at 100 profiles per run total. Paid plan: unlimited. Mode 2 is the most efficient choice when you already have a list — no follower-scraping overhead.

**Why am I being charged per profile, not per run?**
Pay-per-event lets you control spend tightly. Each profile retrieved triggers one $0.002 event; profiles that fail to retrieve (private, deleted, region-blocked) are not billed.

**What happens if a target account is private?**
It's skipped during the discovery phase. You're not charged for the failed retrieval, and the username is recorded in the run summary so you can re-check later.

**Why "N/A" instead of `null` for missing values?**
Every output key is always present so Google Sheets, Airtable, and CSV consumers don't have to special-case missing fields. If you need null, it's a one-line transform in your post-processing.

**How fast is it?**
Roughly 200–400 profiles per minute. A 100-profile run finishes in ~30 seconds; a 1,000-profile run in 4–6 minutes.

**Do I need a TikTok account, login, or cookies?**
No. The actor needs no TikTok login, no cookies, and no session tokens — paste usernames and run. Your own TikTok account (if you have one) is never involved.

**Can I run it on a schedule?**
Yes — Apify Schedules work on every plan, including free. Pair a schedule with `clearSavedData: false` and each scheduled run bills only profiles it hasn't processed before, which makes recurring audience monitoring cheap.

**How do I get more results per run?**
Three things to check, in order: (1) the right mode — make sure the username field of the *selected* `operationMode` is the one you filled; (2) filters — they run after profiles are fetched, so overly strict thresholds can reject everything a run analyzed (start loose, then tighten); (3) plan caps — the free plan reads up to 100 profiles and 3 target accounts per run, and any paid Apify plan lifts both.

### 🔗 Related actors

| Actor | Description |
|---|---|
| [tiktok-profile-scraper](https://apify.com/afanasenko/tiktok-profile-scraper) | **This actor** — TikTok creator discovery and enrichment, 3 modes. |
| [instagram-profile-scraper](https://apify.com/afanasenko/instagram-profile-scraper) | Instagram profiles — 5-mode all-in-one (followers, list, expansion, keyword, location). |
| [instagram-followers-scraper](https://apify.com/afanasenko/instagram-followers-scraper) | Instagram followers / following only — single mode. |
| [instagram-related-profiles-scraper](https://apify.com/afanasenko/instagram-related-profiles-scraper) | Instagram lookalike discovery — expands "Suggested for You" from seed accounts. |
| [youtube-channel-scraper](https://apify.com/afanasenko/youtube-channel-scraper) | YouTube channel discovery and enrichment for partnership outreach. |
| [zillow-property-agent-data-scraper](https://apify.com/afanasenko/zillow-property-agent-data-scraper) | Real-estate listings + agent contacts (Zillow). |

### 🛟 Support & feedback

Found something useful, broken, or worth improving? Three ways to help and stay in the loop:

- ⭐ **Leave a review on the Apify Store** — if this actor saved you time, a quick review helps other users find it and helps the author prioritize.
- 🔖 **Bookmark the actor** — open Apify Console → click the ★ Save icon on the actor page so it shows up in your sidebar for the next run.
- 🐞 **Open an issue on the actor's Apify Store page** — bug reports, feature requests, and edge cases all welcome via the Issues tab.

### ⚖️ Is it legal to scrape TikTok?

Scraping publicly available data — including public TikTok profiles — is legal in the United States and most other jurisdictions. The seminal case is *hiQ Labs v. LinkedIn* (9th Cir. 2019, reaffirmed 2022), which held that scraping public web data does not violate the Computer Fraud and Abuse Act. See [Apify's overview of web-scraping legality](https://blog.apify.com/is-web-scraping-legal/) for a deeper read.

That said, three responsibilities sit with you:

1. **TikTok's Terms of Service** — review and use the data in line with what they permit.
2. **Personal data laws** (GDPR / CCPA / CAN-SPAM / similar) — public profiles still contain personal data; make sure you have a legitimate basis to process it, and respect contact preferences in any outreach (clear unsubscribe path, double opt-in for emails).
3. **Downstream use** — TikTok's data is volatile (categories, ER, language detection drift); verify critical fields against the live profile before acting on them. The author makes no representation about accuracy or fitness for a specific purpose.

If unsure about a specific use case, consult legal counsel.

# Actor input Schema

## `operationMode` (type: `string`):

Operation mode — selects how profiles are sourced. "analyzeFollowersFollowing" (Mode 1) scrapes the followers and/or following of one or more target accounts. "analyzeSpecificAccounts" (Mode 2) enriches a list of usernames you provide. "analyzeEngagedAudience" (Mode 3) discovers users actively commenting on a target account's posts.

## `targetUsernames` (type: `array`):

Target accounts for Mode 1 — TikTok usernames or full profile URLs (one per line, case-insensitive). The actor scrapes each target's followers and/or following list as input candidates for enrichment. Free plan: up to 3 target accounts per run. Start with a big public creator (e.g. willsmith) to verify your setup, then switch to your own targets.

## `analyzeFollowers` (type: `boolean`):

When true, includes the target's followers list as input candidates for analysis. Set false to skip followers (you may still scrape Following separately). At least one of analyzeFollowers / analyzeFollowing must be true.

## `analyzeFollowing` (type: `boolean`):

When true, includes the target's Following list as input candidates for analysis. Off by default — most use cases focus on followers. Combine with analyzeFollowers=true to scrape both lists.

## `maxCount` (type: `integer`):

Maximum number of profiles to collect and analyze in Mode 1 — hard cost ceiling because each profile is one paid event ($0.002). 0 = no limit. Free plan ceiling: 100 profiles per run regardless of this value. Counts every profile fetched, including those filtered out post-fetch.

## `specificUsernamesList` (type: `array`):

Profiles to enrich in Mode 2 — usernames or full profile URLs to look up directly (one per line, case-insensitive). The actor enriches each one with metrics, language, and contacts; it does not scrape their follower lists. Free plan: 100 profiles per run.

## `maxCountList` (type: `integer`):

Maximum profiles from your Mode 2 list to process — hard cost ceiling, $0.002 per profile. 0 = no limit. Useful when you paste a long list but want to spend only N events this run.

## `engagedAudienceTargetUsernames` (type: `array`):

Target accounts for Mode 3 — usernames or profile URLs whose engaged commenters you want to discover (one per line). The actor reads each target's recent posts, collects unique commenters, then enriches every one of them. Free plan: up to 3 target accounts.

## `maxEngagedProfiles` (type: `integer`):

Maximum unique engaged profiles to collect and analyze in Mode 3 — hard cost ceiling, $0.002 per profile. 0 = no limit. Use it to bound a discovery run when a target's posts have thousands of commenters.

## `extractEmail` (type: `boolean`):

When true, the actor parses any email address out of the bio text and emits an Email column. Set false to skip; the Email column will then be omitted from the output. No extra API call — derived from data already fetched.

## `extractWebsiteUrl` (type: `boolean`):

When true, captures the bio link URL when one is set on the profile and emits a Website column. Set false to omit the column. No extra API call.

## `postExtractionMode` (type: `string`):

Post-caption extraction mode — controls whether and how recent video captions are emitted as Post 1, Post 2, … columns. "none" (default) skips post-text capture for cheaper runs. "recent" returns the most recent posts; "popular" returns the most-viewed. Required when keywordLocation is "posts" or "anywhere".

## `numberOfPosts` (type: `integer`):

Number of post captions to emit when postExtractionMode is set — controls how many Post N columns appear (Post 1 through Post N). Range 1–20. Default 8. No effect when postExtractionMode is "none".

## `keywords` (type: `array`):

Keyword filter — only include profiles where any keyword appears (case-insensitive OR-match) in the location chosen by keywordLocation. Empty = no keyword filter. Examples: «fitness, workout, training», «luxury, travel, hotel». Multi-word phrases match as substrings.

## `keywordLocation` (type: `string`):

Where to look for keyword matches — "bio\_or\_name" (default) checks bio text and display name; "bio" / "name" / "posts" target one location only; "anywhere" combines all three. "posts" and "anywhere" require postExtractionMode to be "recent" or "popular".

## `profileLanguages` (type: `string`):

Language filter — only include profiles whose detected content language matches your selection. Detection runs on post captions first (most accurate), bio as fallback; profiles with very little text show N/A and are dropped when a specific language is selected here. "any" disables the filter.

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

Minimum follower count — profiles below this are skipped. 0 = no minimum. Combine with maxFollowers for a band (e.g. 1 000–10 000 for nano-influencers, 10 000–100 000 for micro).

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

Maximum follower count — profiles above this are skipped. 0 = no maximum. Useful for excluding mega-accounts when you target nano or micro creators.

## `minLikes` (type: `integer`):

Minimum total likes across all videos on the profile — profiles below this are skipped. 0 = disabled. Total-likes is a coarse signal; combine with engagement-rate filters for quality.

## `minMedianViews` (type: `integer`):

Minimum median views on the profile's ~35 most recent videos — profiles below this are skipped. The median resists outliers (one viral video doesn't inflate it). 0 = disabled. Posts are fetched for this calculation even when postExtractionMode is "none".

## `minAvgShares` (type: `number`):

Minimum average shares on recent videos — profiles below this are skipped. Share count is a virality signal independent of follower size. 0 = disabled.

## `minEngagementRatio` (type: `number`):

Minimum engagement rate filter, as a percentage — profiles below this are skipped. Computed as ((avg likes + avg comments + avg shares) / followers) \* 100 over the recent video sample. 0 = disabled. Typical thresholds: 1–3 % for mid-size creators, 5 %+ for highly engaged niches.

## `lastPostDays` (type: `integer`):

Last-post-recency filter — only include profiles that posted within the last N days. 0 = disabled. Examples: 7 for very active creators, 30 for typical-active, 90 for any-recent. Profiles with no posts are dropped when this is set.

## `accountType` (type: `string`):

Keep only one kind of account. «Any» is the default. TikTok has three: business and creator are both professional, personal is an ordinary account. Measured on 139 accounts from real runs: personal 77%, creator 11%, business 11% — so any filter here cuts the list hard. Running an influencer campaign? Pick «Creator», not «Personal».

## `mustBeVerified` (type: `boolean`):

When true, only profiles with the TikTok blue verification checkmark pass. Off by default. Useful for celebrity/brand-only campaigns; far too restrictive for general influencer discovery.

## `filterForInfluencers` (type: `boolean`):

When true, only profiles with a creator/influencer category (Public Figure, Musician/Band, Creator & Influencer, Sports/Fitness, Beauty, etc.) pass — filters out brands and uncategorized accounts. Off by default. Use it for influencer marketing where brand pages are noise.

## `categoryFilter` (type: `string`):

Business-category filter — restrict to profiles labeled with the chosen TikTok business category. "any" disables. The list mirrors TikTok's own taxonomy: Public Figure, Musician/Band, Sports/Fitness, Shopping & Retail, Beauty, Food & Beverage, Travel, Health, Education, Finance, Tech, Automotive, Real Estate, Gaming, and more.

## `clearSavedData` (type: `boolean`):

When true (default), the actor clears any checkpoint data from previous runs and starts fresh. Set false to resume — the run continues from the last successfully processed batch instead of re-scraping. Useful after an aborted run or when iterating on filters with the same target list.

## `maxBudgetUsd` (type: `number`):

Maximum spend in USD for this run — the actor stops gracefully when the budget is about to be exceeded. 0 uses the platform default ($5 on free plans, $1 000 on paid). Each profile retrieved is $0.002, so a $5 cap covers up to ~2 500 profiles before auto-stop.

## Actor input object example

```json
{
  "operationMode": "analyzeFollowersFollowing",
  "targetUsernames": [
    "willsmith"
  ],
  "analyzeFollowers": true,
  "analyzeFollowing": false,
  "maxCount": 0,
  "specificUsernamesList": [
    "therock",
    "khaby.lame"
  ],
  "maxCountList": 0,
  "engagedAudienceTargetUsernames": [
    "willsmith"
  ],
  "maxEngagedProfiles": 0,
  "extractEmail": true,
  "extractWebsiteUrl": true,
  "postExtractionMode": "none",
  "numberOfPosts": 8,
  "keywords": [],
  "keywordLocation": "bio_or_name",
  "profileLanguages": "any",
  "minFollowers": 0,
  "maxFollowers": 0,
  "minLikes": 0,
  "minMedianViews": 0,
  "minAvgShares": 0,
  "minEngagementRatio": 0,
  "lastPostDays": 0,
  "accountType": "any",
  "mustBeVerified": false,
  "filterForInfluencers": false,
  "categoryFilter": "any",
  "clearSavedData": true,
  "maxBudgetUsd": 0
}
```

# Actor output Schema

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

No description

## `metrics` (type: `string`):

No description

## `rawItems` (type: `string`):

No description

## `downloadCsv` (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 = {
    "operationMode": "analyzeFollowersFollowing"
};

// Run the Actor and wait for it to finish
const run = await client.actor("afanasenko/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 = { "operationMode": "analyzeFollowersFollowing" }

# Run the Actor and wait for it to finish
run = client.actor("afanasenko/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 '{
  "operationMode": "analyzeFollowersFollowing"
}' |
apify call afanasenko/tiktok-profile-scraper --silent --output-dataset

```

## MCP server setup

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