# TikTok Video Scraper 🎵 Comments, Views & Engagement (`gatherworks/tiktok-video-scraper`) Actor

Paste TikTok video URLs and export the video plus its comment thread. Views, likes, shares, saves, hashtags, music, duration and engagement rate, with every comment carrying the video it belongs to. No login, no cookies, no API key.

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

## Pricing

from $2.20 / 1,000 videos

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 Video Scraper 🎵 Comments, Views & Engagement

**Paste TikTok video links and get the video — views, likes, shares, saves,
hashtags, music and a calculated engagement rate.** Switch on the **comments
add-on** and every comment arrives as its own row.

**No account, no cookies, no API key.** Paste links and run.

***

### 🔍 What is the TikTok Video Scraper?

Give it TikTok video URLs, copied straight from the app or the web. Bare video
IDs work too. For each one it returns:

- 🎬 the video — caption, views, likes, comments, shares, saves, duration
- 📈 an engagement rate computed from those counts
- 🏷️ hashtags, mentions and the sound used

Switch on the **comments add-on** and the thread comes too, comment by comment.

### ⚡ What can it do?

- **🔗 Take links exactly as you copied them.** No ID extraction, no tidying up.
- **💬 Collect the whole comment thread** *(add-on — off by default)*, or cap it
  at a number you choose.
- **🔢 Filter comments by likes** and drop the noise.
- **🚧 Cap how far a filter searches**, so a narrow filter stops rather than
  running away with your budget.
- **⚠️ Report a video it cannot reach**, rather than dropping it silently.
- **📄 Export anywhere.** JSON, CSV, Excel — the dataset is yours.

#### 🎯 Every comment is a comment on the video

The thread comes back as comments made directly on the video, so a count taken
over it is a count of what people said to the creator — not a mix of those and
replies people made to each other, which quietly inflates every figure you
compute from it. `repliesCount` on each row tells you how much conversation a
comment started.

### ⚡ Speed and accuracy

**Speed.** Measured on a real run with the comments add-on on: **1 video and
25 comments in 2 seconds**.

**Accuracy.** Comments are de-duplicated by ID, so a paging overlap never
double-counts. Counts are numbers, not display text. Timestamps are ISO 8601.
Engagement rate is computed from the raw counts on the same row, so you can check
it. Hashtags come from the video's own entity list rather than a regex over the
caption. A video that cannot be reached is written to the dataset as an `error`
row with the input you gave and a plain-English reason, so a short dataset is
never a silent one.

### 📊 What data does it return?

**Video rows** (`rowType: "video"`) — returned on every run:

| Field | Notes |
|---|---|
| 📝 `videoCaption`, `captionLength` | The caption and its length |
| 🔗 `videoUrl` | Direct link to the video |
| 📊 `viewsCount`, `likesCount`, `commentsCount`, `sharesCount`, `savesCount` | Engagement, as numbers |
| 📈 `engagementRate`, `engagementTotal` | Engagement as a percentage of views, and as a total |
| ⏱️ `durationSeconds` | Video length |
| 🏷️ `hashtags`, `mentions` | Lifted from the caption's entity list |
| 🎵 `musicTitle`, `musicAuthor` | The sound used |
| 🖼️ `coverUrl`, `playUrl` | Cover image and video file |
| 🏷️ `authorHandle`, `authorDisplayName` | Who posted it |

**Comment rows** (`rowType: "comment"`) — only with the **comments add-on** on:

| Field | Notes |
|---|---|
| 💬 `commentText` | The comment |
| 📊 `likesCount`, `repliesCount` | Engagement on the comment — including how many replies it drew |
| 🏷️ `authorHandle`, `authorDisplayName` | Who wrote it |
| ✅ `authorIsVerified` | Whether the author carries a verified badge |
| 📅 `publishedAt` | When it was written, ISO 8601 |

#### 🚫 What it does **not** return

- **Videos from private accounts.** They are not publicly visible.
- **Deleted or region-blocked videos.**
- **Analytics only the video's owner can see** — watch time, audience demographics.
- **Direct messages or drafts.**

### 💰 How much does it cost?

You pay per event, for what the run actually produces — never for runtime, and
never on a subscription.

Standard rate: **💵 $0.0037 per video**. Comments are an add-on at **💵 $0.0015
each**, and are off unless you switch them on:

| Run | Cost |
|---|---|
| 🟩 100 videos, no comments *(the default run)* | 💵 $0.37 |
| 🟨 10 videos + 50 comments each *(add-on on)* | 💵 $0.79 |
| 🟧 100 videos + 100 comments each *(add-on on)* | 💵 $15.37 |

**A video that cannot be reached is free.** So is a comment your filters remove.
**A month you do not run it costs nothing at all** — there is no plan to keep alive.

#### What you get for that

| | Included here |
|---|---|
| 📈 Engagement rate computed per video | ✅ |
| 🔀 Replies marked and linked to their parent | ✅ *(comments add-on)* |
| 🏷️ Hashtags and mentions as arrays | ✅ free |
| 🎵 Music title and author | ✅ free |
| ⚠️ Unreachable videos reported, not dropped | ✅ free |
| 💳 Minimum spend | none |

### 🚀 How do I use it?

1. Paste one or more **TikTok video URLs**.
2. Run as-is for the videos alone — that is the default, and the `video` rate
   is the only charge it makes.
3. Or switch on **💬 Include the comment thread** — it is off by default — to add
   the thread, and set **maximum comments per video** to control what that costs.
4. Run, then export the dataset as JSON, CSV or Excel.

### ⚙️ Input

| Field | Notes |
|---|---|
| 🔗 `videoUrls` | TikTok video URLs or bare video IDs |
| 💬 `includeComments` | Collect the comment thread. **Add-on — off by default** |
| 🔢 `maxCommentsPerVideo` | Cap comments collected per video |
| 🔢 `minLikes` | Keep only comments with at least this many likes |
| 🚧 `maxScanned` | How many comments a like filter may skip before stopping — default **300** |

```json
{
  "videoUrls": [
    "https://www.tiktok.com/@tiktok/video/7106594312292453675"
  ],
  "includeComments": false,
  "maxCommentsPerVideo": 50
}
```

### 📄 Output example

Real rows, captured from a live run.

**A default run returns `video` rows only:**

```json
[
  {
    "rowType": "video",
    "videoUrl": "https://www.tiktok.com/@tiktok/video/7106594312292453675",
    "authorHandle": "tiktok",
    "viewsCount": 578042,
    "likesCount": 98785,
    "commentsCount": 1333,
    "engagementRate": 17.382,
    "durationSeconds": 25
  }
]
```

**With the comments add-on switched on, `comment` rows are added alongside them:**

```json
[
  {
    "rowType": "comment",
    "commentText": "j thought it was 16 because of the emoji😳",
    "authorHandle": "t3ss51",
    "likesCount": 182,
    "repliesCount": 1
  }
]
```

### ❓ Frequently asked questions

**Do I need a TikTok account?** No. No account, no cookies, no API key.

**What link formats work?** Full video URLs copied from the app or the web, and
bare video IDs.

**Are comments included by default?** No. The comment thread is an add-on and is
**off by default** — a default run returns videos and is charged the `video` rate
and nothing else.

**Are comments charged at the video rate?** No — comments are cheaper, and a
video-only run costs only the video rate.

**Do I get replies to comments?** No — the thread comes back as comments made
directly on the video. `repliesCount` tells you how many replies each one drew.

**Can I find videos by keyword or creator instead of pasting links?** For a
creator's videos, use the TikTok Profile Scraper.

### 🏷️ Pricing

Pay per event — you are charged for output, not for platform time.

| Event | Price | Covers |
|---|---|---|
| 🎬 `video` — **primary** | 💵 $0.0037 | One video returned. **The only charge a default run makes** |
| 💬 `comment` — **add-on** | 💵 $0.0015 | One comment under that video. Only when `includeComments` is on |
| ▶️ `apify-actor-start` | 💵 $0.00005 | Starting one run, charged once per GB of memory |
| 📊 Views, likes and engagement rate | ✅ **free** | On every video row |
| 🔎 Filtering and sorting | ✅ **free** | Filtered-out comments are not charged for |
| ❌ Links that do not resolve | ✅ **free** | Reported, never charged |

**The add-on is off by default.** Leave it off and you are charged the `video`
rate and nothing else — one charge per video returned, and no other charge.

#### 🏅 Rates by tier

The prices above are the standard rate. Higher Apify plans are billed at the
discounted tiers below, automatically:

| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| 🎬 `video` | 💵 $0.0037 | 💵 $0.0032 | 💵 $0.0027 | 💵 $0.0022 |
| 💬 `comment` | 💵 $0.0015 | 💵 $0.0013 | 💵 $0.0011 | 💵 $0.0009 |
| ▶️ `apify-actor-start` | 💵 $0.00005 | 💵 $0.00005 | 💵 $0.00005 | 💵 $0.00005 |

#### 🛑 You are never billed past your limit

Set a maximum charge on the run and the Actor stops when it reaches it, with
every video collected up to that point complete and saved. Filtered-out comments
are never stored and never billed.

# Actor input Schema

## `videoUrls` (type: `array`):

Paste video links straight from the app or the web. Both forms work: <code>https://www.tiktok.com/@tiktok/video/7106594312292453675</code> or a bare video ID.

## `includeComments` (type: `boolean`):

Collect the comments underneath each video. <b>Off by default</b> — switch it on and each comment is returned as its own row and billed as an add-on.

## `maxCommentsPerVideo` (type: `integer`):

Caps how many comments are collected under each video. Cost scales linearly with this number.

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

Keep only comments with at least this many likes. The videos you asked for are always returned.

## `maxScanned` (type: `integer`):

Only applies when a minimum like count is set. Caps how many comments the filter may reject before the Actor stops and returns what it found, so a narrow filter cannot walk an entire thread. Comments it keeps do not count towards this, and the effective limit is never more than six times the comments-per-video limit.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.tiktok.com/@tiktok/video/7106594312292453675"
  ],
  "includeComments": false,
  "maxCommentsPerVideo": 50,
  "maxScanned": 300
}
```

# Actor output Schema

## `videos` (type: `string`):

One row per video requested, plus a row per comment when the comments add-on is switched on.

# 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 = {
    "videoUrls": [
        "https://www.tiktok.com/@tiktok/video/7106594312292453675"
    ]
};

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

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

```

## MCP server setup

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