# TikTok Scraper: Videos, Profiles, Comments, Sounds & Places (`nextgensda/tiktok-scraper`) Actor

Scrape TikTok videos, profiles, hashtag feeds, keyword searches, sounds, places, followers, Shop products and comments. Full metadata: description, author, plays, likes, comments, shares, saves, music, video URLs, covers. No browser and no login; 256 MB.

- **URL**: https://apify.com/nextgensda/tiktok-scraper.md
- **Developed by:** [Tauqeer Abbas](https://apify.com/nextgensda) (community)
- **Categories:** Social media, Lead generation, AI
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 83.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.18 / 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.

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 Scraper: Videos, Profiles, Comments, Sounds, Places & Shop

![TikTok Scraper: videos, profiles, comments, sounds, places, followers and Shop products, with no browser and pay-per-event pricing from $0.18 per 1,000 videos](https://api.apify.com/v2/key-value-stores/E7K0352HgebdUa0lF/records/banner.png?signature=1GP3M2bk7WFeTAOHzJ5Ik)

TikTok data at **$0.18 per 1,000 videos** — one actor for videos, profiles,
keyword search, hashtags, sounds, places, followers/following lists, user
search, comments, replies and TikTok Shop products.

**No browser, no login, no device. 256 MB. Runs in seconds.**

### Why this actor

|  | This actor | Browser-based TikTok scrapers |
|---|---|---|
| **Price per 1,000 videos** | **$0.18** | $0.30 – $3.70 |
| **Per 1,000 comments** | **$0.06** | $0.30 – $1.25 |
| **Per 1,000 profiles** | **$0.12** | $0.30 – $3.00 |
| Browser / Chrome | none | Chromium + residential proxy per session |
| Memory | **256 MB** | 1 – 4 GB |
| Login required | no | often |
| One actor for every surface | **yes** | usually split into 5–10 actors |
| Output compatibility | native, **Clockworks-style** or **apidojo-style** keys | one fixed shape |

Because there is no browser in the loop, runs start in seconds, stay inside a
quarter of a gigabyte, and a full video row costs a fraction of a cent.
De-duplication is applied across all inputs, so you never pay twice for the
same video.

### Built for AI datasets

Every row is stable, flat and de-duplicated — ready for training, evaluation and
retrieval pipelines without a cleaning pass:

- **Pre-training and fine-tuning corpora** — descriptions, hashtags, mentions and
  author metadata with stable ids and timestamps.
- **Multimodal datasets** — a playable video URL, cover and dynamic cover, music
  metadata and duration for every item.
- **Sentiment and topic models** — comment text with likes, reply counts,
  language and the video it belongs to.
- **Trend and engagement forecasting** — plays, likes, comments, shares and
  saves per video, plus creation time, so you can build time series.
- **Retrieval and RAG** — search results, hashtag feeds and profiles as a
  knowledge base for agents.
- **Commerce and recommendation** — TikTok Shop products behind each video
  (product id, title, seller) for recommendation and demand models.
- **Geo and spatial models** — place pages with coordinates, city and category.
- **Audio and sound matching** — sound pages with title, author, duration and
  play URL for audio fingerprints and sound recommendation.

Export as JSON, CSV, Excel or XML, stream to your warehouse on a schedule, or
deliver through webhooks and the Apify API.

### What you get

One row per item, with `dataType`:

| `dataType` | Fields |
|---|---|
| `video` | id, URL, description, created date, author (id, @handle, nickname, sec uid, verified, bio, avatar), plays, likes, comments, shares, saves, reposts, music (id, title, author, original, play URL), video URL, download URL, cover, dynamic cover, dimensions, definition, hashtags, mentions, discovery source |
| `profile` | id, URL, @handle, nickname, sec uid, bio, verified, private, avatar, followers, following, hearts, video count |
| `comment` | id, video id/URL, text, created date, likes, reply count, pinned, language, author |
| `sound` | id, URL, title, author, owner, duration, original, commerce flag, video count, cover, play URL, created date |
| `location` | place id, URL, name, address, city, country, category, latitude/longitude, video count, favourite count, cover |
| `product` | product id, title, seller ids, image, anchor type, and the video it was found on |

Duplicates are removed across all inputs. `includeComments` adds one row per
comment of every delivered video; `includeReplies` adds their replies.

### Quick start

1. **Videos** — paste video URLs (`https://www.tiktok.com/@user/video/123…`)
   or numeric IDs.
2. **Profiles** — paste profile URLs, `@handles` or `sec_uid`s. Each profile
   comes with its recent videos (up to *Max videos per profile*).
3. **Searches** — keywords; ~110 videos per broad query, plus *Search
   variants* for more.
4. **Hashtags** — `cats`, `#cats` or a tag URL.
5. **Sounds** — sound URLs or ids: the sound's page plus the videos using it.
6. **Locations** — place URLs or ids: the place plus the videos posted there.
7. **Followers of / Following of** — profiles whose follower list to read.
8. **User searches** — keywords to find users by name or handle.
9. **For You feed** — N videos from the algorithmic feed (optional).

Everything can be combined in one run.

### Input

| Input | Default | Notes |
|---|---|---|
| `videos` | — | video URLs or IDs |
| `profiles` | — | URLs, `@handles`, `sec_uid`s |
| `searches` | — | keywords |
| `hashtags` | — | tags |
| `sounds` | — | sound URLs or ids |
| `locations` | — | place URLs or ids |
| `followersOf` | — | profiles whose followers to list |
| `followingOf` | — | profiles whose following to list |
| `userSearches` | — | user keywords |
| `feedItems` | `0` | feed items (0 = off) |
| `maxVideosPerProfile` | `20` | 0 = profile rows only |
| `maxItemsPerSearch` | `120` | search depth per keyword or hashtag |
| `maxItemsPerSound` | `100` | 0 = the sound row only |
| `maxItemsPerLocation` | `100` | 0 = the location row only |
| `maxFollowersPerProfile` | `200` | accounts listed per profile |
| `maxUsersPerSearch` | `20` | profile rows per user keyword |
| `region` | `US` | ISO code whose catalogue to read |
| `postedWithinDays` | `0` | 0 = any date; 1/7/30/90/180 days |
| `sortBy` | `relevance` | `relevance`, `likes` or `latest` (searches) |
| `searchVariants` | `2` | extra requests per keyword for more depth |
| `outputFormat` | `native` | `native`, `clockworks` or `apidojo` |
| `includeComments` | `false` | one row per comment of each video |
| `maxCommentsPerVideo` | `50` | |
| `includeReplies` | `false` | also read replies |
| `maxRepliesPerComment` | `0` | 0 = no reply reads |
| `includeProducts` | `false` | one `product` row per Shop-anchored video |
| `maxItems` | `1000` | total rows |
| `requestDelayMs` | `250` | pacing between requests |
| `proxyConfiguration` | Apify Proxy | datacenter by default |

### Output formats

`outputFormat` changes the row's field names, not what is scraped:

| Value | Shape |
|---|---|
| `native` | this actor's flat schema (`dataType`, `authorUniqueId`, `playCount`, …) |
| `clockworks` | `authorMeta`, `musicMeta`, `videoMeta`, `diggCount`, `playCount`, `webVideoUrl`, `createTimeISO`; comments use `cid`, `awemeUrl` |
| `apidojo` | `views`, `likes`, `comments`, `shares`, `bookmarks`, `channel`, `video`, `song`, `postPage` |

The mappings are field-compatible, not byte-identical: values that TikTok does
not publish (a video's author follower counts, song album, hashtag ids) stay
`null` instead of being invented. `sound`, `location` and `product` rows are
always in the native shape.

### Pricing

Pay per event — you pay only for the rows you receive:

| Event | Price |
|---|---|
| `video` | **$0.18 / 1,000** |
| `profile` (also followers/following rows) | **$0.12 / 1,000** |
| `comment` | **$0.06 / 1,000** |
| `sound` | **$0.06 / 1,000** |
| `location` | **$0.06 / 1,000** |
| `product` | **$0.06 / 1,000** |
| Actor start | $0.001 per run |

Set a **maximum cost per run** and the actor stops when it is reached; nothing
beyond your limit is delivered or charged.

### Notes and limits

- A keyword search returns up to ~110 videos; *Search variants* asks the
  topic's own hashtags again for more (measured 110 → 130+). Narrow, multi-word
  keywords return fewer.
- `postedWithinDays` uses TikTok's own date filter, which narrows the same
  result pool: short windows return far fewer videos. Hashtag feeds are
  filtered locally because TikTok ignores the filter there.
- `region` selects the catalogue to read (measured: two runs in one region
  share ~90% of their videos, two regions ~55%).
- The For You feed is algorithmic: not reproducible run to run.
- `vm.tiktok.com` short links are not expanded: open the link and use the
  redirected URL.
- Private or deleted videos and profiles are skipped and not charged.
- Shop products come from the video's own Shop anchor; TikTok does not publish
  a product catalogue to a logged-out session.

# Actor input Schema

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

TikTok video URLs (<code>https://www.tiktok.com/@user/video/123…</code>) or numeric video IDs. Full metadata, including the playable video URL. <code>vm.tiktok.com</code> short links are not supported: open the link and copy the redirected URL.

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

Profile URLs, <code>@handles</code> or <code>sec_uid</code>s. A row per profile (followers, following, hearts, videos, bio), plus its recent videos up to <b>Max videos per profile</b>.

## `searches` (type: `array`):

Video results for each keyword, in TikTok's order. TikTok returns about 80 distinct videos per query; use more specific queries for more.

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

Videos in each hashtag's feed (<code>cats</code>, <code>#cats</code> or a <code>tiktok.com/tag/…</code> URL).

## `sounds` (type: `array`):

Sound URLs (<code>tiktok.com/music/…-123</code>) or numeric sound ids. One <code>sound</code> row (title, author, duration, cover, play URL, video count) plus the videos that use it, up to <b>Max videos per sound</b>.

## `locations` (type: `array`):

Place URLs (<code>tiktok.com/place/…-123</code>) or numeric place ids. One <code>location</code> row (name, address, city, category, coordinates, video count, cover) plus the videos posted there, up to <b>Max videos per location</b>.

## `userSearches` (type: `array`):

Keywords to find users by (name or handle): a profile row per match, up to <b>Max users per search</b>.

## `followersOf` (type: `array`):

Profiles whose <b>followers</b> to list (URL, <code>@handle</code> or sec_uid): one <code>profile</code> row per follower, up to <b>Max followers per profile</b>. Works without a TikTok login.

## `followingOf` (type: `array`):

Profiles whose <b>following</b> list to read: one <code>profile</code> row per account they follow.

## `feedItems` (type: `integer`):

Videos from the For You feed, in TikTok's algorithmic order for the selected region (US by default). 0 disables it; the feed is not reproducible between runs.

## `maxVideosPerProfile` (type: `integer`):

Recent videos to read for each profile above. 0 = profile rows only.

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

Two-letter country code (US, GB, DE, JP…) whose catalogue to read. Empty = US. This is a data filter, not a proxy setting: results differ (two runs in one region share ~90% of their videos, two regions ~55%).

## `postedWithinDays` (type: `integer`):

0 = any date. Otherwise TikTok's own search filter is used (1, 7, 30, 90 or 180 days). It filters the same candidate pool the search would return, so a short window returns far fewer videos (measured: 1–4 for a generic keyword in 1–30 days). Hashtags are filtered on our side because their stream ignores the filter.

## `sortBy` (type: `string`):

TikTok's search ordering. Applies to keyword searches only.

## `searchVariants` (type: `integer`):

Extra requests per keyword, one per hashtag that two or more results carry (for example <code>cat #catsoftiktok</code>), which returns a different slice of the topic. One request answers ~50–110 videos and does not paginate, so this is the depth lever: each variant adds ~10–15 videos. 0 = the single stream only.

## `outputFormat` (type: `string`):

Field layout of each row. <b>Native</b> is this actor's own flat schema. <b>Clockworks</b> emits <code>authorMeta</code>, <code>musicMeta</code>, <code>videoMeta</code>, <code>diggCount</code>, <code>webVideoUrl</code>, <code>createTimeISO</code>. <b>apidojo</b> emits <code>views</code>/<code>likes</code>, <code>channel</code>, <code>video</code>, <code>song</code>, <code>postPage</code>. Values TikTok does not publish (a video's author follower counts, song album, hashtag ids) are null, not invented.

## `maxItemsPerSearch` (type: `integer`):

Videos kept per keyword or hashtag. One search stream answers ~50–110 videos; <b>Search variants</b> adds more.

## `maxUsersPerSearch` (type: `integer`):

Profile rows kept per keyword in <b>User searches</b>.

## `maxItemsPerSound` (type: `integer`):

Videos read for each sound above. 0 = the sound row only.

## `maxItemsPerLocation` (type: `integer`):

Videos read for each place above (9 per API request). 0 = the location row only.

## `maxFollowersPerProfile` (type: `integer`):

Accounts listed per input in <b>Followers of</b> / <b>Following of</b> (20 per API request).

## `maxItems` (type: `integer`):

The run stops after this many rows (videos, profiles and comments together).

## `requestDelayMs` (type: `integer`):

Milliseconds between API requests. Raising it is gentler on TikTok; lowering it makes runs faster.

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

Read each video's comments and save one row per comment. Applies to every video this run delivers.

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

Comments read per video, in TikTok's order. 0 reads video rows without comments.

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

Also read replies to each comment (one extra request per comment with replies). Needs <b>Include comments</b>.

## `maxRepliesPerComment` (type: `integer`):

Replies saved per comment; 0 disables reply reads even when <b>Include replies</b> is on.

## `includeProducts` (type: `boolean`):

Emit one <code>product</code> row per product a delivered video sells (product id, title, seller, image), read from the video's own Shop anchor. TikTok does not serve a product catalogue to a logged-out app, so products come from videos.

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

The default is Apify Proxy (datacenter): TikTok answers from it directly. If TikTok starts refusing the exits, switch to the RESIDENTIAL group — a new session is used automatically when a request is refused.

## Actor input object example

```json
{
  "videos": [],
  "searches": [
    "funny cats"
  ],
  "feedItems": 0,
  "maxVideosPerProfile": 20,
  "postedWithinDays": 0,
  "sortBy": "relevance",
  "searchVariants": 2,
  "outputFormat": "native",
  "maxItemsPerSearch": 120,
  "maxUsersPerSearch": 20,
  "maxItemsPerSound": 100,
  "maxItemsPerLocation": 100,
  "maxFollowersPerProfile": 200,
  "maxItems": 1000,
  "requestDelayMs": 250,
  "includeComments": false,
  "maxCommentsPerVideo": 50,
  "includeReplies": false,
  "maxRepliesPerComment": 0,
  "includeProducts": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Videos, profiles and comments: description or text, author, plays, likes, comments, followers, date and link.

## `allFields` (type: `string`):

Every field of every row: shares, saves, music, video and cover URLs, dimensions, hashtags, mentions, comment replies and discovery source.

# 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": [],
    "searches": [
        "funny cats"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nextgensda/tiktok-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": [],
    "searches": ["funny cats"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nextgensda/tiktok-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": [],
  "searches": [
    "funny cats"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nextgensda/tiktok-scraper --silent --output-dataset

```

## MCP server setup

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