# TikTok Profile Scraper — Followers, Bio & Stats (`accountable_eel/tiktok-profile-lookup`) Actor

TikTok profile scraper: paste TikTok handles or profile URLs and get one row per profile: display name, bio, verified badge, follower/following/like/video counts, avatar, and bio link. Reads the profile page's own server-rendered data, no login, no cookies. Charged only for a profile actually found.

- **URL**: https://apify.com/accountable\_eel/tiktok-profile-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 successful lookups

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?

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 Lookup: tiktok profile scraper from $2/1k

You give this actor a list of TikTok handles or profile URLs and for each one it returns display
name, bio, verified badge, follower/following/like/video counts, avatar image, bio link, and
whether the account is private. Every field is read straight from the profile page's own
server-rendered data at request time, no login, no cookies, and no third-party database sits
between you and the answer.

### Who it's for

Anyone qualifying, monitoring, or reporting on TikTok creators without opening the app or a
browser tab per profile: agencies vetting creators for an influencer campaign, marketers tracking
a competitor brand's TikTok growth, and analysts who need follower counts in a spreadsheet or a
Clay/n8n workflow instead of a TikTok tab. Pricing is pay-per-event and per-profile: a few tenths
of a cent for a profile that was actually found, and nothing for a miss, so a list with a typo'd
handle or a deleted account costs you nothing extra. No seat license, no monthly minimum, no
credit system to decode.

### Why this one

- **Reads the profile's own live page, not a stale database snapshot.** Every run fetches
  `tiktok.com/@<handle>` fresh, so a creator who gained a million followers an hour ago shows the
  new number, not a cached one.
- **No login, no cookies, no headless browser.** TikTok's profile page embeds the whole profile
  (user info and stats) as JSON in the page's own HTML, so a plain HTTP fetch is enough; no session
  token or account of your own is ever needed.
- **Never charged for a miss.** A handle that's banned, suspended, or never existed still gets a
  row explaining why, and costs nothing. See "Price" below for the found-row rate.
- **Exact follower/like/following/video counts, not TikTok's rounded display figure.** The page
  carries both an abbreviated count ("95.6M") and the exact number behind it; this actor returns
  the exact one.
- **Private accounts still resolve.** A private account's profile-level stats (follower count, bio,
  verified badge) are still public on the page itself; `isPrivate: true` tells you the account is
  locked without failing the lookup.

### What you get

Every row starts with the same five fields, then the profile fields.

| Field | Type | Description |
|---|---|---|
| `query` | text | The handle or URL you submitted, echoed back |
| `found` | boolean | `true` if the profile was found |
| `status` | text | `OK` on a match; `NOT_FOUND`, `BLOCKED`, `BAD_FORMAT`, or `REQUEST_FAILED` on a miss |
| `message` | text | Plain-English reason for a miss, only present when `found` is `false` |
| `scrapedAt` | ISO 8601 datetime | When the page was fetched |
| `handle` | text | The account's TikTok handle (without the `@`) |
| `userId` | text | The account's stable numeric TikTok user ID |
| `nickname` | text | The account's display name |
| `bio` | text | The account's bio/signature text |
| `verified` | boolean | Whether TikTok shows a verified badge on the account |
| `followerCount` | number | Exact follower count |
| `followingCount` | number | Exact following count |
| `heartCount` | number | Total likes across all of the account's videos |
| `videoCount` | number | Total videos posted |
| `avatarUrl` | link | The account's avatar image, largest size available |
| `bioLink` | link | The external link in the account's bio, if it has one |
| `isPrivate` | boolean | Whether the account is set to private |

Deselect any field in the Input tab's column picker to drop it from every row: `query`, `found`,
`status`, `message`, and `scrapedAt` always stay.

### Price

Pay-per-event. A flat per-run fee covers session/proxy warmup; you're billed
per item only when data is actually found and returned — see
`.actor/pay_per_event.json` for exact prices. A miss is never charged.

1,000 profiles through this actor: **~$2** if every one is found, less if some aren't and less
again on a paid Apify plan. A banned, suspended, or nonexistent handle is never billed; you only
pay for a profile you actually got data back for.

### How to use

1. **In the Apify Console.** Open the actor page and click **Start** — the `profiles` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~tiktok-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"profiles":["tiktok","khaby.lame"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

1) Open the Input tab and paste your list into "TikTok handles or profile URLs to look up": one
   per line, as a bare handle (`tiktok`), an `@handle`, or a full profile URL.
2) Leave "Try it first" on for your first run; it caps the run at 5 profiles so you can see the
   output shape before spending on the full list.
3) Optionally narrow the "Which columns do you want?" list if you only need a subset of fields, or
   set "Only keep rows containing" / "Skip rows containing" to filter by keyword.
4) Turn "Try it first" off and press Start to run the full list.

Typical uses: vetting a shortlist of creators before an influencer campaign, tracking a competitor
brand's TikTok follower growth with a scheduled run, or pulling follower/like counts for a list of
handles into a spreadsheet for outreach prioritization.

### Input

```json
{
  "profiles": [
    "tiktok",
    "khaby.lame"
  ]
}
```

One TikTok handle or profile URL per line. Accepted formats: tiktok, @tiktok, https://www.tiktok.com/@tiktok.

### Sample output

| query | found | status | handle | userId | nickname | bio | verified | followerCount | followingCount | heartCount | videoCount | avatarUrl | bioLink | isPrivate | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| tiktok | true | OK | <handle> | <tiktok user id> | <display name> | <bio> | <verified> | <followers> | <following> | \<likes (all videos)> | <videos posted> | <avatar image> | <bio link> | <private account> | 1970-01-01T00:00:00.000Z |

A handle that's banned, suspended, or never existed gets a row with `found: false` and a `status`/
`message` explaining why, and is never charged.

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~tiktok-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"profiles":["tiktok","khaby.lame"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~tiktok-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"profiles":["tiktok","khaby.lame"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~tiktok-profile-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"profiles":["{{profile}}"]}`, mapping the row's profile into the `profiles` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "TikTok Profile Scraper | Apify" — the agent will find and run this actor.

### Tips

- Run "Try it first" on a handful of accounts you already know the follower count for, to
  sanity-check the numbers before running a full list.
- A `NOT_FOUND` status with a "user banned" message means the handle exists in TikTok's records but
  the account is banned or suspended; a handle that never existed reports the same way, since
  TikTok's page doesn't distinguish the two.
- `followerCount`, `followingCount`, `heartCount`, and `videoCount` are exact counts, not TikTok's
  rounded on-page display figure (e.g. "95.6M").
- `bioLink` is `null` for the many accounts that don't set one; it's not a sign of a broken lookup.
- Keep "Max concurrency" conservative on a large list. This target has no browser fallback, so a
  burst of blocked requests costs more in wasted retries than a slower, steadier crawl.

### vs. alternatives

| | What it costs | What you get | Trade-off |
|---|---|---|---|
| **This actor** (`tiktok-profile-lookup`) | $2 per 1,000 found profiles (FREE tier, less on paid tiers), nothing for a miss | One row per profile: display name, bio, verified badge, exact follower/following/like/video counts, avatar, and bio link, read live from the profile's own page | No video-level data in this version — it's profile stats only, not a list of the account's videos. |
| **clockworks/tiktok-profile-scraper** | $3 per 1,000 results | Profile stats plus per-video data and deeper history controls | Broader per-video coverage; this actor trades that for a simpler, faster single-request design when you only need profile-level numbers. |
| Doing it yourself | Your time plus parsing TikTok's internal page JSON, handling banned/suspended accounts, and re-testing as TikTok's markup changes | The same data | This actor's parsing, the banned-vs-not-found distinction, and the exact-vs-rounded count handling are the maintenance burden it absorbs. |

Prices for third-party tools are their published figures as of September 2026 and are not tracked
here; check the vendor before relying on the comparison.

### FAQ

**Why is a row empty, or why does `found` say `false`?**
Either the account is banned, suspended, or never existed (`status: NOT_FOUND`), the request got
blocked (`status: BLOCKED`, usually HTTP 403/429/503), or the request failed after retries
(`status: REQUEST_FAILED`). Check the `message` column for the specific reason. None of these are
billed.

**Am I charged for a miss?**
No. `Actor.charge()` only fires when the profile actually resolves and its data is returned. A
banned account or a blocked request produces a row (unless you turn on "Hide rows with no result")
and costs nothing.

**Is this a live check or a stored database?**
Live. Every run fetches the profile's current page; there's no cached snapshot behind it. Run it on
a schedule if you want to track a creator's growth over time.

**Do I need to configure proxies?**
No. The actor uses Apify's default proxy configuration out of the box; there's nothing to set up
unless you want to supply your own proxy group.

**Is this GDPR-relevant?**
The data returned is an account's own public, self-published profile information (bio, follower
count, avatar) that the account holder chose to make public, not private personal data.

**Why is `bioLink` sometimes empty?**
Most accounts don't set an external link in their bio. It comes back `null` in that case; every
other field is unaffected.

**Does this work on private accounts?**
Yes, for the profile-level fields. TikTok still serves display name, bio, verified badge, and
follower/following/like/video counts for a private account's public profile page; `isPrivate: true`
flags it. What a private account doesn't expose either way is video content, which this actor
doesn't return for any account.

**Can I schedule this to track a creator's growth over time?**
Yes. Set up an Apify Task with a schedule (daily, weekly, whatever cadence fits) and point it at
this actor with a saved input. Each run is a fresh fetch, so a scheduled task combined with your own
storage is how you'd build a follower-growth chart.

**Can an AI agent call this directly?**
Yes. It's registered on the Apify MCP server; an agent in Claude, Cursor, or another MCP client can
find and run it by name ("TikTok Profile Scraper | Apify"), or you can call the REST endpoint shown
above from any script or workflow tool.

### Related actors

- [YouTube Channel Lookup](https://apify.com/accountable_eel/youtube-channel-lookup): the same
  profile-stats pattern, for YouTube channels instead of TikTok accounts.
- [Telegram Channel Lookup](https://apify.com/accountable_eel/telegram-channel-lookup): subscriber
  counts and recent posts for a public Telegram channel.
- [Google News Lookup](https://apify.com/accountable_eel/google-news-lookup): once you've qualified
  a creator or brand, check what news coverage they're getting.

# Actor input Schema

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

One TikTok handle or profile URL per line. Accepted formats: tiktok, @tiktok, https://www.tiktok.com/@tiktok. You're only charged for the ones we actually find — a miss costs nothing.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

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

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

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

Apify Proxy config. Residential recommended for anti-bot-sensitive targets.

## Actor input object example

```json
{
  "profiles": [
    "tiktok",
    "khaby.lame"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "columns": [
    "handle",
    "userId",
    "nickname",
    "bio",
    "verified",
    "followerCount",
    "followingCount",
    "heartCount",
    "videoCount",
    "avatarUrl",
    "bioLink",
    "isPrivate"
  ],
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "profiles": [
        "tiktok",
        "khaby.lame"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

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

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {
    "profiles": [
        "tiktok",
        "khaby.lame",
    ],
    "includeKeywords": [],
    "excludeKeywords": [],
}

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

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

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

```

## CLI example

```bash
echo '{
  "profiles": [
    "tiktok",
    "khaby.lame"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/tiktok-profile-lookup --silent --output-dataset

```

## MCP server setup

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

```

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/g8Rhjie7EoCSKGNNe/builds/9lJDXCYmorcgIwc3a/openapi.json
