# TikTok Comments Scraper & Monitor - Replies, Likes, New Only (`neverempty/tiktok-comments-scraper`) Actor

For brand monitoring, community management and sentiment research: comments of TikTok videos as rows with text, author, likes, reply count, time posted and whether the creator pinned or liked them, with optional replies. Monitoring returns only comments posted since the last run. Unofficial.

- **URL**: https://apify.com/neverempty/tiktok-comments-scraper.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.46 / 1,000 comment row returneds

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 Comments Scraper & Monitor - Replies, Likes, New Only

Export the comments of TikTok videos from their URLs: **the comment text, the author's username and display name, the like count, the reply count, the time it was posted and the comment id**, plus whether the creator pinned or liked it. Turn on replies to get each comment's replies right after it, with the parent comment id and the username replied to.

Turn on **monitoring mode**, schedule the Actor, and each run returns **only the comments posted since the last run**. Videos TikTok returns no comment list for come back as free rows that say so.

Unofficial. Public data only. This Actor is not affiliated with TikTok. It reads the comments TikTok shows to any visitor without logging in, and it does not read private accounts, direct messages or anything behind a login.

### What you can use it for

- **Brand and campaign monitoring**: schedule monitoring mode on your videos or a creator's campaign videos and get only the new comments each hour or day.
- **Community management**: find new questions and complaints under your videos without scrolling.
- **Sentiment and research datasets**: export comments with likes, reply counts, language and time to a spreadsheet, a database or an AI pipeline.
- **Influencer vetting**: see who comments under a creator's videos and how much engagement the comments get.

### How it works

1. Paste video URLs (`https://www.tiktok.com/@nasa/video/7676868860749827342`), photo post URLs (`/photo/`), mobile URLs (`https://m.tiktok.com/v/7676868860749827342.html`) or bare numeric video ids.
2. For each video the Actor reads TikTok's public comment list page by page (`https://www.tiktok.com/api/comment/list/`, up to 50 comments per page) and returns each comment once. Only comments that TikTok labels with the video you asked for are returned.
3. With `includeReplies` on, it reads the replies of every comment that has any (`/api/comment/list/reply/`) and returns them right after their comment.
4. Videos that TikTok returns no comment list for, bot checks and invalid input get a free row that says why.

### Input

| Field | Default | What it does |
| --- | --- | --- |
| `videos` | example videos | Video URLs, photo post URLs or numeric video ids, one per line (commas also separate entries, and so do spaces between entries that are all video URLs or ids). A repeated video is read and charged once; the repeat gets a free `duplicate` row. Short links (`vm.tiktok.com`) are not followed. Up to 500 videos per run. |
| `maxCommentsPerVideo` | `100` | With monitoring off, stop a video after this many rows (comments plus replies). In monitoring mode it limits only the first check of a video. Up to 10,000. |
| `includeReplies` | `false` | Also return replies, as rows of type `reply`. Charged like comments. |
| `monitoringMode` | `false` | Return only comments posted since the last run of each video. |
| `resetMonitoringState` | `false` | Forget everything remembered and start again with a first check. Turn it off again after one run. |
| `useProxy` | `true` | Retry a page through a US proxy only if TikTok answers it with a bot check or a rate limit. |

```json
{
    "videos": [
        "https://www.tiktok.com/@nasa/video/7676868860749827342"
    ],
    "maxCommentsPerVideo": 500,
    "includeReplies": true,
    "monitoringMode": true
}
```

If you leave `videos` out of the input with monitoring off, the two example videos in the input form are read (their URLs appear in `inputVideo` and the run log says so). In monitoring mode `videos` is required, so a schedule never pays to watch the examples. An empty list is rejected with a free `invalid-input` row.

### Output

One row per comment. This row was read from Apify on 2026-09-21 (UTC):

```json
{
    "status": "ok",
    "inputVideo": "https://www.tiktok.com/@nasa/video/7676868860749827342",
    "videoId": "7676868860749827342",
    "videoUrl": "https://www.tiktok.com/@nasa/video/7676868860749827342",
    "videoCommentCount": 1247,
    "commentId": "7676872245000602398",
    "type": "comment",
    "parentCommentId": null,
    "repliedToCommentId": null,
    "repliedToUsername": null,
    "text": "My dream job posted",
    "imageCount": 0,
    "likeCount": 1601,
    "replyCount": 10,
    "createdAt": "2026-08-22T15:05:43.000Z",
    "createTime": 1787411143,
    "language": "en",
    "isPinnedByCreator": false,
    "isLikedByCreator": false,
    "authorUsername": "harlowniederle",
    "authorNickname": "Harlow🌎🌘🚀🇸🇰🇵🇷",
    "authorId": "7449540857897763883",
    "authorSecUid": "MS4wLjABAAAABuTp51IjFEYhZOfE7Q1A_LXqjJ10v_TMSU4LNh2th8favObQE65D0KhEtOed22KB",
    "authorProfileUrl": "https://www.tiktok.com/@harlowniederle",
    "isFirstCheck": null,
    "isNew": null
}
```

Every row also has `source` and `scrapedAt`. Notes on the columns:

- `type` is `comment` or `reply`. A reply has `parentCommentId` (the comment it sits under) and, when it answers another reply, `repliedToCommentId` and `repliedToUsername`. `replyCount` is only filled on comments.
- `text` is `null` for comments with no text, such as a photo or a sticker only; `imageCount` says how many photos a comment has. The text is returned as TikTok shows it.
- `language` is the language TikTok detected for the comment, or `null` when TikTok could not tell.
- `videoCommentCount` is the comment count TikTok shows for the video.
- `videoUrl` is filled when you gave a full video URL; with a bare id it is `null`.
- `isFirstCheck` and `isNew` are filled only in monitoring mode (see below).

#### How many comments you get

TikTok's listing does not reach the comment count it shows. On 2026-09-21, for a NASA video showing **1,249** comments, reading the whole list with replies from Apify returned **623 comments and 209 replies** (832 rows, 117 seconds). So expect fewer rows than the count on the video, and use `videoCommentCount` for the shown figure. On a larger video (Zach King, 66,172 comments shown) the same day, 3,000 comments were read in 271 seconds.

Comments come in TikTok's own order (most relevant first), not by time. TikTok also repeats some comments on later pages (when the same video was read page by page earlier that day, 59 of the 676 comments listed were repeats); each comment is returned once.

### Rows that are never charged

| Status | Meaning |
| --- | --- |
| `video-not-returned` | TikTok returned no comment list and no comment count for the id. It does this for ids that do not exist; it may also mean the video is private, removed or has comments turned off, and the row does not claim which. |
| `no-comments-listed` | TikTok's comment list for the video is empty. |
| `blocked` | TikTok answered with a bot check, a rate limit or an empty response, even after retrying. |
| `unreadable` | The comment list could not be read (`tiktokStatusCode` has TikTok's code when it gave one). |
| `stopped-reading` | Reading a video stopped part way (a later page could not be read, or replies of some comments could not be read). The rows returned before that are complete. |
| `max-comments-reached` | The video reached `maxCommentsPerVideo` rows. |
| `invalid-input` | The entry is not a video URL or id, or it is a short link. |
| `duplicate` | The same video appeared earlier in the list. |
| `no-new-comments` | Monitoring mode: no new comments on the videos checked. |
| `budget-reached` | The run's maximum total charge had no room for more rows (the row says how many comments or videos were left out). |
| `not-checked` | More than 500 videos were given. |

### Pricing

- **$2.00 per 1,000 comment rows** (comments and replies), charged only for rows with `status: "ok"`.
- In monitoring mode, also **$0.30 per 1,000 comment pages read**: every page of up to 50 comments or replies read costs a page check, whether or not it has new comments. Example: 10 videos with about 500 comments each (about 10 pages each) checked every hour is 72,000 pages a month, which is **$21.60**, plus $2.00 per 1,000 new comments returned.

The Actor reads only as many pages as the run's maximum total charge can pay for (in monitoring mode, a page check and a comment row each), and a free row says what was left out.

### Monitoring mode

- The first run of a video returns up to `maxCommentsPerVideo` comments with `isFirstCheck: true` and remembers the time of that check.
- Later runs read the video's whole comment list again (TikTok does not sort it by time) and return only comments posted after the previous check that were not returned before, with `isNew: true`. They are not cut by `maxCommentsPerVideo`.
- To catch comments that appear in TikTok's list a little late, the boundary is placed 10 minutes before each check, and comments already returned inside that window are remembered so they are not returned twice.
- If a run stops part way (for example at the maximum total charge), the boundary does not move, so comments that were not reached are returned by the next run.
- With `includeReplies` on, a comment's replies are read again only when the comment is new or its reply count went up since a check that read it, and only replies posted after the previous check are returned. Comments the first check did not reach (beyond `maxCommentsPerVideo`) have their reply count remembered from the next check on; their replies are read once that count goes up.
- Large videos cost more pages per check: on 2026-09-21 a second check of a NASA video showing 13,593 comments read 200 comment pages (the most read per video) plus reply pages. When a check stops at 200 pages or at the maximum total charge, the boundary does not move, so comments it did not reach are still returned later.
- Comments that were posted before the first check and not returned by it (beyond `maxCommentsPerVideo`) are never returned by later checks.
- The memory is kept per video for this Actor, not per list. **Do not put the same video in two schedules that can run at the same time**: Apify's key-value store has no atomic update, so two runs of the same video finishing together can overwrite each other.
- If Apify restarts or moves a run, it continues after the videos it had already finished, and a comment already in the run's dataset is not returned or charged again.

### Limits

- Up to 500 videos per run, read one page at a time with a short pause between requests. Up to 200 comment pages per video and 20 reply pages (1,000 positions) per comment; a free row says when a comment had more replies than that.
- The Actor does not search TikTok or list a creator's videos; give it the video URLs.
- It does not follow short links (`vm.tiktok.com`); open one in a browser and paste the full URL.

# Actor input Schema

## `videos` (type: `array`):

Videos to read the comments of: https://www.tiktok.com/@nasa/video/7676868860749827342 (with or without the scheme; photo posts /photo/ work too), https://m.tiktok.com/v/7676868860749827342.html, or the numeric video id. One per line (commas also separate entries, and so do spaces between entries that are all video URLs or ids). Short links (vm.tiktok.com) are not followed: open one in a browser and paste the full video URL. A repeated video is read and charged once and the repeat gets a free 'duplicate' row. If you leave this field out with monitoring off, two example videos are read; with monitoring on it is required. An empty list is rejected.

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

With monitoring off, reading a video stops once this many charged rows (comments plus replies) have been returned for it, and a free row says so. In monitoring mode it limits only the first check of a video; later checks return every new comment found, as far as the run's maximum total charge allows. TikTok's own listing ends before its shown comment count on many videos (on 2026-09-21 a video showing 1,249 comments listed 623 comments and 209 replies).

## `includeReplies` (type: `boolean`):

On = after each comment that has replies, its replies are read and returned as rows of type 'reply' with the parent comment id and the username replied to. Replies are charged like comments and count toward maxCommentsPerVideo. In monitoring mode a comment's replies are read again only when it is new or its reply count went up. Off = only top-level comments, with their reply count.

## `monitoringMode` (type: `boolean`):

Off = every run returns the video's comments, charged per row. On = the first run of a video returns up to maxCommentsPerVideo comments and remembers the time of that check; later runs read the whole comment list again and return only comments posted after the previous check that were not returned before. **In monitoring mode every page of comments read (up to 50 comments, or replies) costs $0.30 per 1,000 pages, whether or not it has new comments**, plus the row price for the comments returned. Example: 10 videos with about 500 comments each (about 10 pages each) checked every hour = 72,000 pages a month = $21.60. The Actor reads only as many pages as the run's maximum total charge can pay for with a page check and a comment row each. Remembered per video; do not put the same video in two schedules that can run at the same time.

## `resetMonitoringState` (type: `boolean`):

Clears everything remembered for every video, so the next monitoring run treats each video as a first check again. This affects all your monitoring runs, because the memory is stored per video rather than per list. Turn it off again after one run: left on in a schedule, every run is a first check and charges for up to maxCommentsPerVideo comments per video.

## `useProxy` (type: `boolean`):

Every page is requested directly first. Only if TikTok answers a page with a bot check, a rate limit (HTTP 429), an empty response or no response is that page retried through a proxy session located in the United States; the next page is requested directly again. With it off, that answer is retried directly and then returned as a free 'blocked' row, and no proxy is paid for.

## Actor input object example

```json
{
  "videos": [
    "https://www.tiktok.com/@nasa/video/7676868860749827342",
    "https://www.tiktok.com/@zachking/video/6745555903166041349"
  ],
  "maxCommentsPerVideo": 100,
  "includeReplies": false,
  "monitoringMode": false,
  "resetMonitoringState": false,
  "useProxy": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per TikTok comment (and per reply when replies are turned on): the comment text, the author's username, display name and profile URL, the like count, the reply count, the time it was posted, the comment id, the language TikTok detected and whether the creator pinned or liked it; for replies, the parent comment id and the username replied to. In monitoring mode only comments posted since the last check are returned. Videos TikTok returns no comment list for, bot checks and invalid input come back as free rows that say why.

# 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 = {
    "videos": [
        "https://www.tiktok.com/@nasa/video/7676868860749827342",
        "https://www.tiktok.com/@zachking/video/6745555903166041349"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/tiktok-comments-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 = { "videos": [
        "https://www.tiktok.com/@nasa/video/7676868860749827342",
        "https://www.tiktok.com/@zachking/video/6745555903166041349",
    ] }

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

```

## MCP server setup

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