# TikTok Profile Scraper: Followers, Bio & User Posts (No Login) (`stanvanrooy6/tiktok-profile-scraper`) Actor

Scrape TikTok profiles and user posts from any profile URL or @handle: exact follower count, bio, verification and every public video with views, likes, comments and shares. No login, no cookies, no API key. Pay per result. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/stanvanrooy6/tiktok-profile-scraper.md
- **Developed by:** [Stan Van Rooy](https://apify.com/stanvanrooy6) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 3 total users, 2 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 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.
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: Followers, Bio & User Posts (No Login) 👤

The TikTok Profile Scraper extracts **profile data and every public post** from any TikTok profile URL or @handle, with **no login, no cookies and no third-party API key**. Paste a handle, set how many posts you want, and download clean, structured data as JSON, CSV or Excel, or pull it straight from the Apify API.

Built for influencer discovery, creator vetting, competitor tracking, content research and audience analytics.

### 🚀 How to scrape TikTok profiles

1. Paste one or more TikTok profile URLs or @handles (sec\_uid values and numeric user IDs work too).
2. Set **Max posts per profile** (default 100, or 0 for the full public feed).
3. Click **Start**.

That is it. No TikTok account, no browser extension, no proxy setup on your side.

Each run writes one **profile row** per handle and one **post row** per video, in the same dataset, so you can join them by handle. Switch either off with `includeProfile` or `includePosts` if you only need one of the two.

### 📊 What data can you scrape from a TikTok profile?

**Per profile**

- Handle, display name, user ID and the stable sec\_uid
- Bio, link in bio and profile picture
- Exact follower, following, likes (hearts), video and friend counts (not the rounded 95.8M you see on the page)
- Verified badge, private account flag, business account and TikTok Shop seller flags
- Account language, region when TikTok exposes it, and the account creation date
- Linked Instagram, YouTube and X handles when the creator connected them
- A `status` field: `ok`, `private`, `not_found`, `blocked` or `unavailable`, so banned, deleted and private handles still produce a row you can act on

**Per post**

- Video ID, URL, caption, publish date and 1-based rank in the feed (newest first, pinned posts first)
- Play, like, comment, share, save, download and repost counts
- Hashtags and mentioned user IDs
- Music ID, title, artist and whether it is an original sound
- Duration, resolution, cover image, playable MP4 URL and download URL
- Image URLs for photo carousels, TikTok's own subtitle tracks when present
- Pinned and ad flags, video region

Every row carries `type` (`profile` or `post`), `platform`, `source_url` and, for posts, `profile_unique_id`, so joining posts back to profiles in your own pipeline is one key.

### 📥 Input

| Field | Type | Notes |
|---|---|---|
| `profiles` | array | Profile URLs (`https://www.tiktok.com/@handle`), `@handles`, sec\_uid values (`MS4wLjAB...`) or numeric user IDs. `vm.tiktok.com` short links are followed. **Required.** |
| `maxPostsPerProfile` | integer | Cap on posts per profile, newest first. `0` collects the full publicly available feed. Default `100`. |
| `includeProfile` | boolean | Write the profile row. Default `true`. |
| `includePosts` | boolean | Write post rows. Default `true`. |
| `region` | string | Residential proxy country and app identity for the post feed. Default `US`. Profiles are global, so keep `US` unless you scrape region locked content. |

Minimal input:

```json
{
  "profiles": ["@tiktok", "https://www.tiktok.com/@charlidamelio"],
  "maxPostsPerProfile": 100
}
```

### 📤 Output

#### Profile row

```json
{
  "type": "profile",
  "status": "ok",
  "status_reason": null,
  "user_id": "5831967",
  "sec_uid": "MS4wLjABAAAA-VASjiXTh7wDDyXvjk10VFhMWUAoxr8bgfO1kAL1-9s",
  "unique_id": "charlidamelio",
  "nickname": "charli d'amelio",
  "bio": "orca enthusiast\nmeg thee stallion fan",
  "bio_link": "https://m.youtube.com/@CharlidAmelio",
  "avatar_url": "https://p16-common-sign.tiktokcdn-eu.com/....jpeg",
  "verified": true,
  "private": false,
  "region": null,
  "language": "en",
  "follower_count": 160164191,
  "following_count": 1441,
  "heart_count": 12339573642,
  "video_count": 3245,
  "digg_count": 0,
  "friend_count": 1255,
  "commerce_user": false,
  "tt_seller": false,
  "is_organization": false,
  "category": null,
  "instagram": null,
  "youtube_channel_id": null,
  "twitter": null,
  "created_at": "2015-11-14T12:57:18.000Z",
  "profile_url": "https://www.tiktok.com/@charlidamelio",
  "platform": "tiktok",
  "source_url": "https://www.tiktok.com/@charlidamelio",
  "scrape_region": "US"
}
```

#### Post row

```json
{
  "type": "post",
  "video_id": "7680996287877008670",
  "url": "https://www.tiktok.com/@tiktok/video/7680996287877008670",
  "desc": "the songs of the summer 2026 #songsofthesummer2026",
  "create_time": "2026-08-31T20:28:58.000Z",
  "create_timestamp": 1788371338,
  "author": {"id": "107955", "sec_uid": "MS4wLjAB...", "unique_id": "tiktok", "nickname": "TikTok", "follower_count": 95838017, "verified": true},
  "stats": {"play": 4100000, "digg": 210000, "comment": 3100, "share": 4200, "collect": 9800, "download": 1200, "repost": 0},
  "music": {"id": "7212600172143085570", "title": "original sound", "author": "TikTok", "original": true},
  "hashtags": ["songsofthesummer2026"],
  "mentions": [],
  "duration": 59.051,
  "width": 720,
  "height": 1280,
  "cover_url": "https://p19-common-sign.tiktokcdn-us.com/....jpeg",
  "play_url": "https://v19.tiktokcdn-us.com/.../video/tos/...",
  "download_url": "https://v19.tiktokcdn-us.com/.../video/tos/...",
  "images": [],
  "subtitles": [],
  "is_pinned": true,
  "is_ad": false,
  "is_image_post": false,
  "region": "US",
  "profile_unique_id": "tiktok",
  "rank": 1,
  "platform": "tiktok",
  "source_url": "@tiktok"
}
```

The dataset has two ready-made views, **Profiles** and **Posts**, so you can export either table on its own.

### ✨ Why this TikTok profile scraper

- **No login, no cookies, no API key.** The scraper creates its own anonymous session for every run. You never hand over a TikTok account, and there is no separate paid API subscription to buy.
- **Exact counts.** Follower, following, likes and video counts come as exact integers, not the rounded figures shown on the page.
- **Posts from TikTok's own feed.** Post rows come from the same feed the TikTok app reads, newest first, with pinned posts flagged, so you get engagement counts, music, hashtags, cover and video URLs in one pass.
- **Banned, private and deleted handles do not break the run.** They produce a profile row with a `status` and a reason, and the run carries on with the next handle.
- **Batch friendly.** Hundreds of handles per run, duplicates collapsed automatically (the same creator given as a URL, a handle and a sec\_uid is scraped once).
- **Joinable schema.** Post rows share the same video schema as my other TikTok scrapers, so search results, video lookups and profile feeds line up.
- **Clean exports.** JSON, CSV or Excel from the Apify Console, or fetch results from the Apify API.
- **Pay per result.** $3.00 per 1,000 profiles and $1.50 per 1,000 posts, no monthly plan.

### 💡 Use cases

- **Influencer discovery and vetting:** Pull exact follower counts, engagement per post and posting cadence for a list of creators before you reach out.
- **Competitor tracking:** Monitor rival brand accounts and their newest posts on a schedule.
- **Content research:** Mine captions, hashtags and sounds from the creators that win in your niche.
- **Lead generation:** Enrich a list of handles with bio links, business flags and linked social accounts.
- **Audience analytics:** Feed post level stats into your own BI, NLP or LLM workflow.

### 🔌 TikTok profile API alternative: run it from code

Every Apify Actor is also an API. If you need TikTok profile data inside your own app or notebook and do not want to apply for TikTok's official Research API, call this scraper with the Apify client:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("stanvanrooy6/tiktok-profile-scraper").call(run_input={
    "profiles": ["@tiktok", "@charlidamelio"],
    "maxPostsPerProfile": 50,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "profile":
        print(row["unique_id"], row["follower_count"])
    else:
        print(row["profile_unique_id"], row["video_id"], row["stats"]["play"])
```

The same works from JavaScript, cURL or any HTTP client. See the **API** tab above for ready-made snippets and the dataset endpoints.

### ⚠️ Limits and good to know

- Posts come newest first, in TikTok's own feed order. There is no "most popular" sort for anonymous clients; sort the post rows by `stats.play` or `stats.digg` yourself.
- TikTok limits how deep one anonymous session can page into a creator's feed. The scraper rotates to a fresh session and carries on from where it stopped, so full feeds of several thousand posts come back complete (3,032 posts for a creator with 3,262 public videos in one test run, the rest being private or unavailable). If every session is challenged it logs a clear message and finishes successfully with the posts it has.
- Follower and following lists (who follows whom) are login gated on TikTok and are not part of this scraper.
- Video and download URLs are signed by TikTok and expire after a few hours. Download what you need right after the run, or re-run to refresh them.
- Private accounts return a profile row with `status: "private"` and no posts. Deleted or banned handles return `status: "not_found"`.
- If a profile page is challenged on every attempt the row is marked `status: "blocked"`; re-running usually lands a clean residential IP.
- A run that collects no rows at all exits with an error and a reason, so an empty result never looks like success.

### 💰 Pricing

This Actor uses **pay per event**, so there is no monthly subscription and you only pay for what you scrape.

- **Profiles:** $3.00 per 1,000 profile rows ($0.003 each). Every row includes exact counts, bio, links and flags.
- **Posts:** $1.50 per 1,000 post rows ($0.0015 each).
- **Run start:** $0.002 per GB of memory, under one cent for a default run.

Scraping 100 creators with their latest 100 posts each costs about $15.30. Comparable TikTok profile scrapers charge $5.00 per 1,000 results for profiles and posts alike. New Apify accounts include monthly free usage credit, which is enough to try the scraper at no cost.

### 🎯 Example inputs

**Profile data only for a list of creators:**

```json
{
  "profiles": ["@tiktok", "@charlidamelio", "@khaby.lame"],
  "includePosts": false
}
```

**Full public feed of one creator:**

```json
{
  "profiles": ["https://www.tiktok.com/@tiktok"],
  "maxPostsPerProfile": 0
}
```

**Latest 20 posts, no profile rows, from a sec\_uid:**

```json
{
  "profiles": ["MS4wLjABAAAAv7iSuuXDJGDvJkmH_vz1qkDZYo1apxgzaxdBSeIuPiM"],
  "maxPostsPerProfile": 20,
  "includeProfile": false
}
```

### ❓ FAQ

#### Do I need a TikTok account or login?

No. The scraper runs fully anonymous and cookie free. You never share credentials.

#### Do I need a third-party API key?

No. Everything runs inside the Actor. Some competing TikTok scrapers require you to bring a separate paid API key. This one does not.

#### Is there a free TikTok profile scraper?

You can run this one for free within the monthly free usage credit that comes with every new Apify account. After that it is $3.00 per 1,000 profiles and $1.50 per 1,000 posts with no subscription.

#### How many posts can I get per profile?

Set `maxPostsPerProfile` to any number, or `0` for the full available feed. TikTok limits how deep anonymous clients can page, so very large accounts may stop before their oldest videos. See the limits section above.

#### Can I get follower lists or who a creator follows?

No. TikTok only shows those lists to logged in users, and this scraper never logs in.

#### Are the follower counts exact?

Yes. The profile row carries TikTok's exact integers, not the rounded 1.2M style figures.

#### What format can I export?

JSON, CSV and Excel from the Apify Console, or straight from the Apify API and dataset endpoints. Use the Profiles and Posts dataset views to export either table alone.

#### Is it legal to scrape TikTok profiles?

The scraper only collects publicly visible data that any anonymous visitor can see, and it does not log in or bypass access controls. Profiles and posts contain personal data, so handle it in line with GDPR, CCPA and your own use case. If you are unsure, consult a lawyer.

#### Can you add a field I need?

Yes. Open an issue on the Issues tab and describe what you need. I actively maintain this Actor and add requested fields and filters.

### 🤝 Feedback and feature requests

I actively maintain this Actor. Found a bug or need a field? Open an issue on the Issues tab.

### 🔗 Related TikTok scrapers

All four share the same no-login engine and output conventions.

- **[TikTok Shop Scraper](https://apify.com/stanvanrooy6/tiktok-shop-scraper)**: TikTok Shop reviews, star ratings and product data from any product URL, up to 25,000 reviews per product.
- **[TikTok Search Scraper](https://apify.com/stanvanrooy6/tiktok-search-scraper)**: search TikTok videos by keyword in any region, with views, likes, hashtags and author data.
- **[TikTok Comments Scraper](https://apify.com/stanvanrooy6/tiktok-comments-scraper)**: export every comment and reply thread from any TikTok video, no login.

Typical workflow: find videos with the TikTok Search Scraper, pull the audience conversation with the TikTok Comments Scraper, profile the creators behind them with the TikTok Profile Scraper, and check what their TikTok Shop products are really rated with the TikTok Shop Scraper.

# Actor input Schema

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

TikTok profile URLs (https://www.tiktok.com/@handle), @handles, sec\_uid values (MS4wLjAB...) or numeric user IDs. Short links (vm.tiktok.com) are followed. One profile row plus its posts per entry.

## `maxPostsPerProfile` (type: `integer`):

Cap on posts collected per profile, newest first (pinned posts come first). Set to 0 for the full publicly available feed.

## `includeProfile` (type: `boolean`):

Write one profile row per handle (follower count, bio, verification, counts).

## `includePosts` (type: `boolean`):

Write one row per post (video stats, hashtags, music, cover and play URLs).

## `region` (type: `string`):

Country of the residential proxy and the app identity used for the post feed. Profiles are global; keep US unless you scrape creators whose content is region locked.

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

Alternative Apify request list input. Merged with the Profiles field above.

## Actor input object example

```json
{
  "profiles": [
    "@tiktok",
    "https://www.tiktok.com/@charlidamelio"
  ],
  "maxPostsPerProfile": 100,
  "includeProfile": true,
  "includePosts": true,
  "region": "US"
}
```

# Actor output Schema

## `rows` (type: `string`):

All scraped rows as JSON. Append ?format=csv or ?format=xlsx for other formats.

## `profiles` (type: `string`):

Profile rows as JSON.

## `posts` (type: `string`):

Post rows as JSON.

## `dataset` (type: `string`):

The default dataset of this run.

# 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",
        "https://www.tiktok.com/@charlidamelio"
    ]
};

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

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

```

## MCP server setup

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