# TikTok Scraper — Profiles, Videos & Hashtags (`bgfc97/tiktok-profile-videos-scraper`) Actor

🔥 Up to 10% OFF! Scrape TikTok profiles, videos & hashtags — 43 fields/video (engagement, transcripts, music) + bio emails + instant profile analytics (avg views, posting frequency, top hashtags). No login, dirt cheap. ⚡

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

## Pricing

from $1.16 / 1,000 videos

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 & Videos Scraper 🎵

**Scrape TikTok profiles, their videos AND hashtags — with engagement, transcripts, music, bio contacts and ready-made profile analytics — no login, no API key, no cookies.** Drop in usernames and/or hashtags and get rich, clean JSON for research, dashboards and lead generation.

**Everything is included in one price** — no paid "add-ons" for transcripts, filters, hashtags or analytics like the big-name scrapers charge. And we're a **fraction of their cost.**

> 🧮 **Bonus most scrapers don't give you:** every profile comes with computed **analytics** — average views, engagement rate, posting frequency, last-post date and top hashtags — perfect for vetting creators in seconds.

***

### ✨ What you get

#### Per profile

- `username`, `nickname`, `userId`, `secUid`
- `bio`, `bioLink`
- **`email`, `phone`** — auto-extracted from the bio (great for lead gen) 💡
- `category`, `isBusinessAccount`
- `followers`, `following`, `likes` (total hearts), `videoCount`, `friendCount`
- `verified`, `privateAccount`, `region`, `avatarUrl`, `profileUrl`
- **`videoStats` (computed analytics)** 🧮 — `avgPlays`, `medianPlays`, `avgLikes`, `avgComments`, `avgShares`, `avgSaves`, `avgEngagementRate`, `lastPostISO`, `daysSinceLastPost`, `postsPerWeek`, `topHashtags`

#### By hashtag

Pass `hashtags` to pull the top/recent videos for any tag — same rich 43-field video objects, plus the same `videoStats` summary (e.g. which hashtags trend together).

#### Per video (newest first, pinned on top) — **43 fields**

- `id`, `desc`, `createTime` (+ ISO), `webUrl`
- **Engagement**: `playCount`, `diggCount` (likes), `commentCount`, `shareCount`, `collectCount` (saves), `repostCount`, and a computed **`engagementRate`** (%)
- **Discovery**: `hashtags[]`, `mentions[]`, `topics[]` (TikTok's own labels), `language`, `categoryType`
- **Content flags**: `isAIGC` (AI-generated), `isAd`, `isPaidPartnership`, `duetEnabled`, `stitchEnabled`, `commentsDisabled`
- **Transcript / subtitles**: `subtitles[]` (language + downloadable URL), `hasSubtitles` — *the big scrapers charge extra for this; here it's free*
- **Media**: `duration`, `width`, `height`, `ratio`, `definition`, `sizeBytes`, `coverUrl`, `dynamicCoverUrl`, `videoUrl`, `downloadUrl`, and **`videoQualities[]`** (every resolution/bitrate with a direct URL)
- **Music / sound**: `music` (id, title, author, original, duration, playUrl)
- **Extras**: `location` (POI name/address/city), `anchors[]` (shopping / place links), `stickerText[]` (on-screen captions), `isPinned`

***

### 🚀 Why this Actor

- **No TikTok login or API key** — works out of the box.
- **Richer than the competition** — 43 fields per video, including transcripts, engagement rate, hashtags, music and AI-content flags, **all bundled** — no nickel-and-dime add-ons.
- **Built-in lead gen** — e-mails and phones pulled straight from bios. The big scrapers don't do this.
- **Filters that save you money** — grab only recent videos or only popular ones, so you never pay for noise.
- **Reliable** — patient scrolling + automatic IP rotation and retries. Small/medium accounts return every video; very large accounts return roughly the newest ~100-150 (TikTok's own logged-out limit).
- **Great value** — just **$0.00129 per video** (**$1.29 / 1,000 videos**, from $1.16 on higher plans) — still a fraction of the $3+/1,000 the big names charge, and far richer. Profile-only runs (`videosLimit: 0`) bill one unit per profile.

***

### 🧭 Use cases

1. **Influencer discovery & vetting** — follower counts, total likes, real engagement rates and bio contacts across a shortlist before you spend on a campaign.
2. **Competitor & brand monitoring** — posting cadence, which videos win, which hashtags and sounds they ride.
3. **Content & trend research** — top videos by play count, topics and AI-content flags to model your own hooks.
4. **Lead generation** — pull creators' e-mails/phones from bios in bulk.
5. **Datasets & dashboards** — clean JSON into Sheets, BI tools or your own ML pipeline via the Apify API.

***

### ⚙️ Input

| Field | Type | Description |
|---|---|---|
| `usernames` | array | TikTok accounts: `@handle`, `handle`, or profile URL. |
| `hashtags` | array | Hashtags to scrape (the `#` is optional). Use with or instead of usernames. |
| `videosLimit` | integer | Newest videos per profile/hashtag. `0` = profile stats only. Default `30` (max 200). |
| `onlyPostsNewerThan` | string | Optional. Keep only videos on/after this date (e.g. `2025-01-01`). |
| `minPlays` | integer | Optional. Keep only videos with at least this many plays. |
| `maxRetriesPerProfile` | integer | Extra attempts (fresh IP) if videos come back empty. Default `2`. |
| `proxyConfiguration` | object | Proxy to use. **RESIDENTIAL is required** for video data. |

#### Example input

```json
{
  "usernames": ["@tiktok", "https://www.tiktok.com/@nasa"],
  "videosLimit": 50,
  "onlyPostsNewerThan": "2025-01-01",
  "minPlays": 10000,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

***

### 📦 Example output (trimmed)

```json
{
  "username": "redbull",
  "nickname": "Red Bull",
  "followers": 7000000,
  "likes": 120000000,
  "videoCount": 1800,
  "email": null,
  "category": "Sports",
  "videos": [
    {
      "id": "74...","desc": "Send it. #redbull #mtb","createTimeISO": "2026-...Z",
      "playCount": 1500000, "diggCount": 99000, "commentCount": 2918, "shareCount": 3189,
      "collectCount": 5120, "repostCount": 42, "engagementRate": 8.91,
      "hashtags": ["redbull","mtb","bike"], "mentions": ["bragevestavik"],
      "language": "en", "isAIGC": false, "duration": 25, "ratio": "540p",
      "videoQualities": [{ "quality": "normal_720_0", "bitrate": 1853378, "url": "https://..." }],
      "subtitles": [{ "language": "eng-US", "format": "webvtt", "url": "https://..." }],
      "music": { "id": "73...", "title": "original sound - Red Bull", "original": true },
      "webUrl": "https://www.tiktok.com/@redbull/video/74..."
    }
  ]
}
```

***

### 💡 Tips

- **Keep the RESIDENTIAL proxy on.** TikTok serves empty results to datacenter IPs.
- Use `onlyPostsNewerThan` / `minPlays` to pull just what you need and keep costs down.
- Private accounts return profile stats with an empty `videos` array.
- Video URLs are TikTok-signed and expire — download promptly if you need the file.

***

### ❓ FAQ

**Do I need a TikTok account or API key?** No.
**Is this allowed?** It reads only data publicly visible on tiktok.com. You are responsible for complying with TikTok's terms and applicable laws.
**Why residential proxy?** TikTok blocks datacenter traffic on its video API; residential IPs are required for reliable results.

***

### ⭐ Enjoying this Actor?

If it saved you time, please leave an **honest review** — it helps a lot. Found a bug or want a feature? **Open an Issue** and we'll jump on it fast.

# Actor input Schema

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

Scrape these accounts' profiles + videos. Accepts @handles (e.g. @tiktok), plain handles (tiktok) or full profile URLs. Leave empty if you only want hashtags or searches.

## `hashtags` (type: `array`):

Scrape top/recent videos for these hashtags (the # is optional, e.g. 'fyp' or '#cooking'). Use this instead of, or alongside, usernames.

## `videosLimit` (type: `integer`):

How many videos to collect per profile or hashtag. Set to 0 (profiles only) for profile stats without videos. Small/medium accounts return everything; very large accounts and hashtags are limited by TikTok to roughly the newest ~100-150 while logged out.

## `onlyPostsNewerThan` (type: `string`):

Optional. Keep only videos posted on/after this date. Accepts YYYY-MM-DD (e.g. 2025-01-01) or any ISO date. Leave empty for no date limit.

## `minPlays` (type: `integer`):

Optional. Keep only videos with at least this many plays/views. 0 = no filter.

## `maxRetriesPerProfile` (type: `integer`):

How many extra attempts (with a fresh proxy IP) to make if a profile's videos come back empty. TikTok is aggressive, so 1-2 retries greatly improves reliability.

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

Proxy used to reach TikTok. RESIDENTIAL proxy is strongly recommended (and required for the video endpoint). The cost of the proxy is paid by you.

## Actor input object example

```json
{
  "usernames": [
    "@tiktok",
    "https://www.tiktok.com/@nasa"
  ],
  "hashtags": [
    "cooking",
    "#fyp"
  ],
  "videosLimit": 30,
  "onlyPostsNewerThan": "2025-01-01",
  "minPlays": 0,
  "maxRetriesPerProfile": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "usernames": [
        "tiktok",
        "nasa"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

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

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {
    "usernames": [
        "tiktok",
        "nasa",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

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

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

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

```

## CLI example

```bash
echo '{
  "usernames": [
    "tiktok",
    "nasa"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call bgfc97/tiktok-profile-videos-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bgfc97/tiktok-profile-videos-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/dHkencTG1RAagYyvO/builds/2VwfNZUOJUF5gKJuF/openapi.json
