# (NEW) TikTok Scraper – Videos, Profiles, Hashtags, Comments (`harshmaur/tiktok-scraper`) Actor

Scrape TikTok videos, hashtags, profiles, search, comments and followers from $0.35 per 1,000. Clockworks-compatible input, AI analysis, no login.

- **URL**: https://apify.com/harshmaur/tiktok-scraper.md
- **Developed by:** [Harsh Maur](https://apify.com/harshmaur) (community)
- **Categories:** Social media, Videos
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.35 / 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, Hashtags, Comments, Followers and AI Analysis

Export **TikTok data** to JSON, CSV or Excel: videos with views, likes, comments, shares and saves, creator profiles with follower counts, comments with their replies, followers and following lists, sounds, hashtags and search results. Add watermark-free video downloads, transcripts and AI labels when you need them.

You don't need a TikTok account, cookies or an API key, and there is no proxy to set up. Paste a username, a hashtag, a keyword or a link and press Start.

**Moving from clockworks/tiktok-scraper?** Paste your existing input. The field names are the same (see [Switching from clockworks/tiktok-scraper](#switching-from-clockworkstiktok-scraper)).

### What can this TikTok scraper do?

- **Scrape TikTok profiles.** Get a creator's latest, oldest or most popular videos, their reposts, and the profile data on every row.
- **Scrape TikTok hashtags.** Collect the videos under any hashtag. Turn on exact match to keep only videos whose caption really carries the tag.
- **Search TikTok.** Search videos by keyword, sorted by relevance, likes or date, within a recent period, or list the accounts behind them.
- **Scrape single videos.** Paste video or photo post links, short vm.tiktok.com links, or video IDs. Optionally add the related videos TikTok recommends next to each one.
- **Scrape TikTok sounds.** Paste a music link or ID to get the videos that use the sound.
- **Collect comments and replies.** Set how many comments and how many replies per comment you want.
- **List followers and following.** Get the accounts that follow a profile, or that the profile follows.
- **Download videos and images.** Save MP4 files without the watermark, plus covers, slideshow images, avatars and sound covers.
- **Get transcripts.** Download TikTok's own subtitles, or have AI transcribe videos that have none.
- **Analyze videos with AI.** Label each video with a category, a sponsored flag, a brand-safety flag and sentiment, answer your own yes/no questions, and write a summary or a scene-by-scene description.

### TikTok Scraper: how to use it

1. Add one or more **Profiles**, **Hashtags**, **Search keywords**, **Video URLs** or **Music** links. You can mix them in one run, or paste any TikTok link into **Any TikTok URL**.
2. Set **Videos per profile, hashtag, search or music**. Add **Max videos in total** if you want a hard cap for the whole run.
3. Optional: add date and likes filters, comments, followers, downloads, transcripts or AI analysis.
4. Click **Start**. Rows appear in the dataset while the run is going, and you can download them in any format Apify supports.

#### Example input

This run takes the 50 latest videos from two creators posted since 1 September 2026 with at least 10,000 likes, plus 20 comments with up to 5 replies each per video:

```json
{
  "profiles": ["khaby.lame", "mrbeast"],
  "resultsPerPage": 50,
  "profileSorting": "latest",
  "excludePinnedPosts": true,
  "oldestPostDateUnified": "2026-09-01",
  "leastDiggs": 10000,
  "commentsPerPost": 20,
  "maxRepliesPerComment": 5
}
```

### Scrape TikTok profiles

Add usernames to `profiles`, with or without the @, or paste profile links. Each profile returns up to `resultsPerPage` videos. The author's profile is attached to every video row in `authorMeta`: `name`, `nickName`, `verified`, `signature`, `bioLink`, `fans`, `following`, `heart`, `video`, `region` and more.

- `profileSorting`: `latest` (default), `popular` or `oldest`.
- `profileScrapeSections`: `["videos"]`, `["reposts"]` or both.
- `excludePinnedPosts`: skip the videos a creator pinned to the top, so "latest" means latest.

### TikTok hashtag scraper

Add hashtags to `hashtags`, with or without the #. TikTok's hashtag feed also contains videos that don't carry the tag. Set `hashtagMatch` to `exact` to keep only videos whose caption contains the hashtag. Videos dropped by the filter are not charged, which matters when you track a campaign tag.

Each hashtag video has `searchHashtag` with the tag name and its total views on TikTok.

### TikTok search scraper

Add keywords to `searchQueries` and pick what you want back with `searchSection`:

| `searchSection` | Returns |
| --- | --- |
| `""` (Top) or `"/video"` | Videos for the keyword. Order them with `videoSearchSorting` (`MOST_RELEVANT`, `MOST_LIKED`, `LATEST`) and limit the period with `videoSearchDateFilter` (`ALL_TIME` to `LAST_6_MONTHS`) |
| `"/user"` | The accounts that posted the matching videos, up to `maxProfilesPerQuery` per keyword, as `profile` rows |

Sorting and the search period cost nothing extra.

### Scrape TikTok videos by URL

Paste links to single videos or photo posts into `postURLs`. Short `vm.tiktok.com` and `vt.tiktok.com` share links work, and so do bare video IDs. You get one full row per link, with views, likes, shares, saves, the caption, hashtags, the sound and the creator's profile:

```json
{ "postURLs": ["https://www.tiktok.com/@charlidamelio/video/7137423965982592302"], "commentsPerPost": 50 }
```

Turn on `scrapeRelatedVideos` to also collect the videos TikTok suggests next to each one, up to `resultsPerPage` per link.

### TikTok sound and music scraper

Add sound links (`tiktok.com/music/...`) or music IDs to `musics` to list the videos that use a sound. This shows who picked up a trending audio and how those videos perform. Each row carries the sound in `musicMeta`, and the date and likes filters work here too.

### Filter TikTok videos by date and likes

All filters are free and work together, on profiles, hashtags, search and music:

- `oldestPostDateUnified`: posted on or after a date (`"2026-09-01"`) or within a number of days (`"30"`).
- `newestPostDate`: posted on or before a date.
- `leastDiggs` and `mostDiggs`: at least or at most this many likes.

You can ask for "videos from the last 30 days with more than 50,000 likes" in a single run.

### TikTok comments scraper

Set `commentsPerPost` to collect comments from every scraped video, and `maxRepliesPerComment` to include replies. `topLevelCommentsPerPost` caps comments that are not replies. Comments are rows with `dataType: "comment"` in the same dataset. A reply's `repliesToId` holds the `cid` of the comment it answers, so you can rebuild each thread.

To get the comments of specific videos only, put the links in `postURLs` and set `commentsPerPost`.

### TikTok followers scraper

Set `maxFollowersPerProfile` and `maxFollowingPerProfile` for the profiles in your input. Each account is a row with `dataType: "follower"`. `connectionType` is `follower` or `following`, `connectedTo` is the profile from your input, and `authorMeta` is the account itself.

### Download TikTok videos without watermark

Turn on `shouldDownloadVideos` to save each video's MP4 without the TikTok watermark. TikTok's own video links expire. The saved files stay in the run's key-value store, and their links are in `mediaUrls` on each video row.

You can also save `shouldDownloadCovers`, `shouldDownloadSlideshowImages` (every image of a photo post, listed in `slideshowImageLinks`), `shouldDownloadAvatars` and `shouldDownloadMusicCovers`.

### TikTok transcript and subtitle scraper

`downloadSubtitlesOptions` takes one of four values:

| Value | What you get |
| --- | --- |
| `NEVER_DOWNLOAD_SUBTITLES` | Nothing (default) |
| `DOWNLOAD_SUBTITLES` | TikTok's own captions, linked in `videoMeta.subtitleLinks` |
| `DOWNLOAD_AND_TRANSCRIBE_VIDEOS_WITHOUT_SUBTITLES` | Captions, plus an AI transcript for videos that have none |
| `TRANSCRIBE_ALL_VIDEOS` | An AI transcript for every video |

The text lands in `videoMeta.transcript`, and `videoMeta.transcriptSource` says whether it came from TikTok's `subtitles` or from `ai`.

### TikTok AI video analysis

Turn on `aiAnalysis` and every video gets an `aiAnalysis` object:

- `category`: one of `comedy`, `food`, `beauty_fashion`, `fitness_sports`, `music_dance`, `gaming`, `education`, `tech`, `travel`, `home_diy`, `pets_animals`, `family_kids`, `business_finance`, `news_politics`, `art_creativity`, `automotive` or `other`
- `sponsored`: whether the video looks like paid promotion
- `brandSafe`: whether a brand could safely appear next to it
- `sentiment`: `positive`, `neutral` or `negative`
- `answers`: your own yes/no questions from `aiQuestions` (up to 20), each answered `true`, `false` or `null` when the AI is unsure

Two more options watch and listen to the video itself:

- `aiVideoSummary`: a short summary in `videoMeta.aiVideoSummary`.
- `aiVideoDescription`: a timed, scene-by-scene description in `videoMeta.aiVideoDescription`.

Example for influencer vetting:

```json
{
  "profiles": ["khaby.lame"],
  "resultsPerPage": 30,
  "aiAnalysis": true,
  "aiQuestions": [
    "Does the creator promote a product?",
    "Does the video contain swearing?"
  ],
  "aiVideoSummary": true
}
```

### Scrape TikTok as if from another country

Set `proxyCountryCode` to a country (for example `GB` or `DE`) to load TikTok from that region and see the search and hashtag results people there see. It costs nothing extra. Leave it at `None` for the default setting.

### TikTok data output

Every row has a `dataType`: `video`, `comment`, `profile`, `follower` or `failed`. The Output tab has a view for each, and you can filter on `dataType` when you export.

#### Video row

Arrays and nested objects are trimmed here.

```json
{
  "dataType": "video",
  "id": "7694335322922044703",
  "text": "Was the ball out, or was it just my imagination? 🤨#learnfromkhaby #comedy",
  "textLanguage": "en",
  "createTime": 1791477076,
  "createTimeISO": "2026-10-08T16:31:16.000Z",
  "webVideoUrl": "https://www.tiktok.com/@khaby.lame/video/7694335322922044703",
  "playCount": 5000000,
  "diggCount": 600000,
  "commentCount": 10900,
  "shareCount": 18700,
  "collectCount": 35131,
  "repostCount": 0,
  "authorMeta": {
    "id": "127905465618821121",
    "name": "khaby.lame",
    "nickName": "Khabane lame",
    "verified": true,
    "fans": 163000000,
    "heart": 2700000000,
    "video": 1358
  },
  "musicMeta": {
    "musicName": "original sound",
    "musicAuthor": "Khabane lame",
    "musicOriginal": true,
    "musicId": "7694335437137087262"
  },
  "videoMeta": {
    "height": 1280,
    "width": 720,
    "duration": 30,
    "definition": "720p",
    "format": "mp4",
    "transcript": null,
    "transcriptSource": null,
    "aiVideoSummary": null
  },
  "hashtags": [{ "id": null, "name": "comedy", "title": null, "cover": null }],
  "isSlideshow": false,
  "isPinned": false,
  "isAd": false,
  "isSponsored": false,
  "isAiGenerated": false,
  "hasTikTokShopProduct": false,
  "mediaUrls": [],
  "input": "khaby.lame",
  "fromProfileSection": "videos",
  "aiAnalysis": {
    "category": "comedy",
    "sponsored": false,
    "brandSafe": true,
    "sentiment": "positive",
    "answers": { "Does the creator promote a product?": false }
  }
}
```

Other video fields: `locationCreated`, `locationMeta`, `mentions`, `detailedMentions`, `effectStickers`, `slideshowImageUrls`, `slideshowImageLinks`, `duetEnabled`, `stitchEnabled`, `suggestedWords`, `isStory`, `submittedVideoUrl`, `searchQuery`, `searchHashtag`.

#### Comment row

```json
{
  "dataType": "comment",
  "videoWebUrl": "https://www.tiktok.com/@khaby.lame/video/7694335322922044703",
  "cid": "7694337701600068373",
  "createTimeISO": "2026-10-08T16:40:10.000Z",
  "text": "I'm Muslim",
  "diggCount": 5444,
  "replyCommentTotal": 54,
  "repliesToId": null,
  "likedByAuthor": false,
  "pinnedByAuthor": false,
  "uid": "7451523731317228550",
  "uniqueId": "khankingmuhammadjan",
  "commentLanguage": "en",
  "imageUrls": []
}
```

#### Profile, follower and failed rows

- **`profile`**: `input` and the full `authorMeta`.
- **`follower`**: `authorMeta` (the account), `connectedTo` (your input profile), `connectionType` and `connectionDescription`.
- **`failed`**: `errorCode`, `error` and `input`. Codes include `profile_not_found`, `hashtag_not_found`, `music_not_found`, `video_unavailable` and `blocked`.

### No empty runs: free failure rows

When an input can't be scraped, you get a `failed` row that says which input and why, instead of a silently empty dataset. Failed rows are never charged.

```json
{
  "dataType": "failed",
  "errorCode": "profile_not_found",
  "error": "@some.deleted.user does not exist.",
  "input": "some.deleted.user"
}
```

### How much does it cost to scrape TikTok?

Pricing is pay per event. You pay only for rows you receive, and the filters, sorting and region choice add nothing to the price:

| What you get | Price |
| --- | --- |
| Videos | **$0.35 per 1,000 videos** |
| Comments and replies | **$0.20 per 1,000 comments** |
| Followers and following | **$0.25 per 1,000 accounts** |
| Profiles (one per scraped profile, or from profile search) | **$4.00 per 1,000 profiles** |
| AI analysis (labels and your questions) | **$1.50 per 1,000 videos** |
| AI summary, scene description or AI transcript | **$25 per 1,000 started 30-second blocks** (a 45-second video counts as 2) |
| Video download without watermark | **$10 per 1,000 videos** |

Date and likes filters, exact hashtag match, search sorting, region choice, TikTok's own subtitles and image downloads are included. `failed` rows are free.

**Example:** 1,000 videos from a hashtag, each with AI analysis, cost $0.35 + $1.50 = **$1.85**.

The AI options run on paid Apify plans. On the free plan they are ignored, and one run searches up to 40 keywords.

### Switching from clockworks/tiktok-scraper

The input is compatible. Field names follow clockworks/tiktok-scraper, so you can paste a saved input or API payload and run it here: `hashtags`, `profiles`, `searchQueries`, `postURLs`, `resultsPerPage`, `profileScrapeSections`, `profileSorting`, `excludePinnedPosts`, `oldestPostDateUnified`, `newestPostDate`, `leastDiggs`, `mostDiggs`, `maxFollowersPerProfile`, `maxFollowingPerProfile`, `searchSection`, `maxProfilesPerQuery`, `videoSearchSorting`, `videoSearchDateFilter`, `scrapeRelatedVideos`, `commentsPerPost`, `topLevelCommentsPerPost`, `maxRepliesPerComment`, the `shouldDownload…` options, `downloadSubtitlesOptions`, `aiVideoSummary`, `aiVideoDescription` and `proxyCountryCode`.

The output uses the same field names too (`authorMeta`, `musicMeta`, `videoMeta`, `webVideoUrl`, `diggCount`, `playCount` and so on), so existing spreadsheets and scripts keep working.

What is different:

- **Lower flat price.** Filters, sorting and region choice don't add a charge per result.
- **Date and likes filters work together** in one run.
- **Exact hashtag match** drops videos that don't carry the tag.
- **Free failure rows** tell you what went wrong instead of an empty run.
- **Comments, replies and followers are rows in the same dataset**, marked by `dataType`. `commentsDatasetUrl` and `followDatasetUrl` are kept for compatibility but are `null`.
- **AI analysis**: category, sponsored, brand safety, sentiment and your own yes/no questions.
- New fields `startUrls`, `musics`, `maxItems`, `hashtagMatch`, `aiAnalysis` and `aiQuestions`.
- Relative dates can be days, weeks, months or years (`"30"`, `"30 days"`, `"2 weeks"`). `profileScrapeSections: ["stories"]` is accepted but returns no stories: TikTok shows stories only to logged-in users. Fields this actor doesn't use, such as `videoKvStoreIdOrName`, are ignored; downloads always go to the run's own key-value store.

### Fast, light runs

Runs start fast and use little memory (256 MB by default). For many AI summaries or video downloads, 512 MB makes the run about twice as fast.

### Use cases

- **Influencer research.** Compare creators by `fans`, average `playCount` and engagement, and vet their content with AI brand-safety labels.
- **Hashtag campaign tracking.** Count the videos, views and likes under a campaign tag with exact match on, every day.
- **Trend and content research.** Search a topic sorted by likes for the last week and see which formats and sounds take off.
- **Comment and sentiment analysis.** Export comments with replies for a brand's videos and study what people say.
- **Audience research.** List a creator's followers or the accounts they follow.
- **Video archive and transcripts.** Save watermark-free MP4s and transcripts for analysis, captions or AI training sets you have rights to.

### Send TikTok data to Slack, Notion or Google Sheets

Choose an authorized MCP connector in `mcpConnector` and the scraped videos are posted to that app when the run finishes. With a schedule, this gives you a daily feed of a creator's or a hashtag's new videos. If you leave the field empty, nothing is sent anywhere.

### Use the TikTok scraper from AI agents

Claude, ChatGPT, Cursor and other MCP-capable agents can call this actor through Apify's MCP server:

```
https://mcp.apify.com/?tools=harshmaur/tiktok-scraper
```

### TikTok API, schedules and integrations

- **Apify API:** start runs and read the dataset from any language, or use the Python and JavaScript clients.
- **Schedules:** run hourly, daily or weekly to track profiles, hashtags or keywords.
- **Webhooks:** get notified when a run ends.
- **Make, Zapier and n8n:** connect through Apify's integrations or a plain HTTP request to the API.

### FAQ

#### Is it legal to scrape TikTok?

The scraper reads only public data that anyone can see on TikTok without logging in. You are responsible for following the laws in your country and TikTok's terms, especially when you store personal data such as usernames and comments, or republish videos. If in doubt, ask a lawyer.

#### Do I need a TikTok account, cookies or proxies?

No. There is no login and nothing to paste. The scraper handles the connection to TikTok itself.

#### Can I scrape private accounts?

No. Private accounts and their videos are not public, so the scraper can't read them.

#### Why did an input fail?

The `failed` row tells you. `profile_not_found` means the account doesn't exist or is banned, `hashtag_not_found` that the tag has no videos, `video_unavailable` that TikTok removed or hides the video, and `blocked` that TikTok refused every attempt. Failed rows are free.

#### Why did I get fewer videos than I asked for?

TikTok shows a limited number of videos per profile, hashtag and keyword to logged-out visitors, and your filters drop videos that don't match. Split broad topics into narrower keywords or hashtags to collect more.

#### Can I use the input I already have for clockworks/tiktok-scraper?

Yes. Paste it as it is. See [Switching from clockworks/tiktok-scraper](#switching-from-clockworkstiktok-scraper) for the small differences.

#### How do I get only new videos every day?

Schedule a run with `oldestPostDateUnified` set to `"1"` to keep only videos from the last day.

#### Are the video downloads really without watermark?

Yes. `shouldDownloadVideos` saves the MP4 without the TikTok watermark to the run's key-value store, and the link is in `mediaUrls`.

#### What does the AI analysis cost and how accurate is it?

See the pricing table for the price. The labels come from an AI model looking at the caption, cover image and transcript. Questions the model is unsure about come back as `null` instead of a guess.

### More scrapers by the same developer

- [TikTok Shop Scraper](https://apify.com/harshmaur/tiktok-shop-scraper): products, prices, sold counts, stock and sellers from TikTok Shop.
- [Reddit Scraper](https://apify.com/harshmaur/reddit-scraper): posts, comments and user activity from any subreddit or search.
- [YouTube Transcript Scraper](https://apify.com/harshmaur/youtube-transcript-scraper): captions of videos, channels and playlists as text, SRT or VTT.
- [Facebook Ads Library Scraper](https://apify.com/harshmaur/facebook-ads-library-scraper): the ads a brand runs on Meta and how long each has been live.
- [LinkedIn Jobs Scraper](https://apify.com/harshmaur/linkedin-jobs-scraper): public job postings by keyword, location and filters.

# Actor input Schema

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

TikTok usernames to scrape, with or without the @. Each profile returns its videos (up to the number below) with the author's profile data on every row. A profile link such as https://www.tiktok.com/@khaby.lame also works.

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

Hashtags to scrape, with or without the #. Each hashtag returns its videos up to the number below. Turn on 'Exact hashtag match' in the filters to keep only videos that really carry the tag.

## `resultsPerPage` (type: `integer`):

The most videos to take from EACH profile, hashtag, search keyword, music or listing link. Also caps related videos per video URL. Video URLs you paste are always scraped.

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

A hard cap on videos for the whole run, across all inputs. Use it to keep the cost of a large list predictable. Leave empty for no total cap.

## `profileScrapeSections` (type: `array`):

Which tabs of each profile to scrape: the profile's own videos, the videos it reposted, or both.

## `profileSorting` (type: `string`):

Latest returns the newest videos first, Oldest the first videos the account posted, Popular the most played. Applies to the Videos tab.

## `excludePinnedPosts` (type: `boolean`):

Leave out the videos a creator pinned to the top of the profile. Pinned videos are often old, so skipping them keeps a 'latest videos' run truly recent.

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

How many followers of each profile to list. Each follower is one row with dataType 'follower'. 0 skips followers.

## `maxFollowingPerProfile` (type: `integer`):

How many accounts each profile follows to list. Each one is a row with dataType 'follower' and connectionType 'following'. 0 skips this list.

## `oldestPostDateUnified` (type: `string`):

Only keep videos posted on or after this date. Through the API you can also send a number of days, for example 30 for the last 30 days.

## `newestPostDate` (type: `string`):

Only keep videos posted on or before this date. Pair it with the field above for a date window.

## `leastDiggs` (type: `integer`):

Only keep videos with at least this many likes (hearts). Works together with the date filter.

## `mostDiggs` (type: `integer`):

Only keep videos with at most this many likes. Useful to find smaller creators or posts before they take off.

## `hashtagMatch` (type: `string`):

Related returns everything TikTok files under the hashtag, including videos that do not carry it. Exact keeps only videos whose caption contains the hashtag. Videos filtered out are not charged.

## `searchQueries` (type: `array`):

Keywords to search for. Each keyword returns up to 'Videos per profile, hashtag, search or music' videos, or up to 'Profiles per keyword' accounts when the section is Profiles.

## `searchSection` (type: `string`):

Top and Videos both return videos for the keyword, with the order and period options below. Profiles returns the accounts that posted the matching videos, one row each.

## `maxProfilesPerQuery` (type: `integer`):

How many accounts to return per keyword when the search tab is Profiles.

## `videoSearchSorting` (type: `string`):

Order of video search results. No extra charge.

## `videoSearchDateFilter` (type: `string`):

Keep only search results posted within this period. No extra charge.

## `postURLs` (type: `array`):

Links to single TikTok videos or photo posts, including short vm.tiktok.com and vt.tiktok.com links, or bare video IDs. Every link returns one row, or a free failure row that says why it could not be read.

## `scrapeRelatedVideos` (type: `boolean`):

For each video URL, also return the videos TikTok recommends next to it, up to 'Videos per profile, hashtag, search or music'.

## `musics` (type: `array`):

TikTok sound links (tiktok.com/music/…) or music IDs. Each one returns videos that use the sound.

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

Paste TikTok links of any kind in one list: profile, hashtag, search, music or video pages. Each link is handled like the matching field above.

## `commentsPerPost` (type: `integer`):

The most comments, replies included, to collect from each video. 0 skips comments.

## `topLevelCommentsPerPost` (type: `integer`):

Cap on comments that are not replies. Leave empty to let 'Comments per video' decide alone.

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

How many replies to collect under each comment. Replies carry repliesToId, the cid of the comment they answer. 0 skips replies.

## `shouldDownloadVideos` (type: `boolean`):

Save each video's MP4 file, without the TikTok watermark.

## `shouldDownloadCovers` (type: `boolean`):

Save the thumbnail of each video.

## `shouldDownloadSlideshowImages` (type: `boolean`):

Save every image of photo and slideshow posts. Links go to slideshowImageLinks.

## `shouldDownloadAvatars` (type: `boolean`):

Save the author's avatar for each video.

## `shouldDownloadMusicCovers` (type: `boolean`):

Save the cover art of the sound each video uses.

## `downloadSubtitlesOptions` (type: `string`):

Download subtitles saves the captions TikTok already has (links in videoMeta.subtitleLinks). The transcribe options also write a speech-to-text transcript to videoMeta.transcript, either only for videos without captions or for all videos.

## `aiAnalysis` (type: `boolean`):

Adds aiAnalysis to each video: a content category, whether it looks sponsored, whether it is brand safe, and its sentiment.

## `aiQuestions` (type: `array`):

Up to 20 questions answered with true or false for every video, for example 'Does the video show a dog?'. Answers go to aiAnalysis.answers. Needs the AI labels option.

## `aiVideoSummary` (type: `boolean`):

A short summary of what the video is about, from its picture and sound. Saved in videoMeta.aiVideoSummary.

## `aiVideoDescription` (type: `boolean`):

A timed description of what is seen and heard in each scene. Saved in videoMeta.aiVideoDescription.

## `proxyCountryCode` (type: `string`):

Load TikTok from this country, to see the search and hashtag results people there see. None lets the scraper pick the most reliable route.

## `mcpConnector` (type: `string`):

Pick an authorized MCP connector (Slack, Notion, Airtable, Google Sheets, …) to receive the scraped videos. Your credentials stay in Apify and are never exposed to this actor (Apify's proxy injects them). Leave empty to scrape only. Tip: schedule a hashtag or a creator to get new videos in your workspace.

## `mcpMode` (type: `string`):

perPost: one message or record per video. summary: a single digest of the whole run.

## `mcpTarget` (type: `string`):

Where to write — the destination ID the tool needs: a Notion database/page ID, a Google Sheet ID, or a Slack channel. Leave blank for connectors that post to a default location. Advanced shapes go in Arguments JSON below.

## `mcpMessage` (type: `string`):

Template for each message. Use {{field}} placeholders from any video field, nested paths included — common ones: {{text}}, {{webVideoUrl}}, {{authorMeta.name}}, {{playCount}}, {{diggCount}}, {{commentCount}}, {{shareCount}}, {{createTimeISO}}. Missing fields render empty.

## `mcpTool` (type: `string`):

Force a specific tool name on the connector (e.g. send_message, create_page, append_row). Leave empty to auto-detect the connector's write/notify tool.

## `mcpArguments` (type: `object`):

Extra/override arguments merged into each tool call as JSON — e.g. {"channel": "#tiktok"} for Slack. {{field}} placeholders work inside string values too, so you can nest live data into any shape — e.g. Notion: {"properties": {"Title": {"title": \[{"text": {"content": "{{text}}"}}]}, "Link": {"url": "{{webVideoUrl}}"}}}.

## `mcpMaxItems` (type: `integer`):

Safety cap on how many videos are piped to the connector per run (perPost mode). Protects against flooding the destination.

## `mcpServerUrl` (type: `string`):

Advanced/testing only. Connect directly to a raw MCP server URL, bypassing the connector above. For real use prefer a connector — your credentials then stay in Apify. When set, this overrides the connector.

## `mcpServerToken` (type: `string`):

Bearer token for the dev MCP server URL above. A token entered here IS visible to the actor at runtime — for production use an MCP Connector instead. Ignored unless the URL is set.

## Actor input object example

```json
{
  "profiles": [
    "khaby.lame"
  ],
  "resultsPerPage": 10,
  "profileScrapeSections": [
    "videos"
  ],
  "profileSorting": "latest",
  "excludePinnedPosts": false,
  "maxFollowersPerProfile": 0,
  "maxFollowingPerProfile": 0,
  "hashtagMatch": "related",
  "searchSection": "",
  "maxProfilesPerQuery": 10,
  "videoSearchSorting": "MOST_RELEVANT",
  "videoSearchDateFilter": "ALL_TIME",
  "scrapeRelatedVideos": false,
  "commentsPerPost": 0,
  "maxRepliesPerComment": 0,
  "shouldDownloadVideos": false,
  "shouldDownloadCovers": false,
  "shouldDownloadSlideshowImages": false,
  "shouldDownloadAvatars": false,
  "shouldDownloadMusicCovers": false,
  "downloadSubtitlesOptions": "NEVER_DOWNLOAD_SUBTITLES",
  "aiAnalysis": false,
  "aiVideoSummary": false,
  "aiVideoDescription": false,
  "proxyCountryCode": "None",
  "mcpMode": "perPost",
  "mcpMessage": "*@{{authorMeta.name}}* — {{diggCount}} likes · {{playCount}} views\n{{text}}\n{{webVideoUrl}}",
  "mcpMaxItems": 50
}
```

# Actor output Schema

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

Video rows with caption, author, views, likes, comments, shares, sound and optional AI fields.

## `comments` (type: `string`):

Comment and reply rows.

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

Profile rows.

## `followers` (type: `string`):

Follower and following rows.

## `failed` (type: `string`):

Inputs that could not be scraped, with the reason. Not charged.

# 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": [
        "khaby.lame"
    ],
    "resultsPerPage": 10,
    "profileScrapeSections": [
        "videos"
    ],
    "maxFollowersPerProfile": 0,
    "maxFollowingPerProfile": 0,
    "commentsPerPost": 0,
    "maxRepliesPerComment": 0,
    "proxyCountryCode": "None",
    "mcpMode": "perPost",
    "mcpMessage": `*@{{authorMeta.name}}* — {{diggCount}} likes · {{playCount}} views
{{text}}
{{webVideoUrl}}`,
    "mcpMaxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("harshmaur/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 = {
    "profiles": ["khaby.lame"],
    "resultsPerPage": 10,
    "profileScrapeSections": ["videos"],
    "maxFollowersPerProfile": 0,
    "maxFollowingPerProfile": 0,
    "commentsPerPost": 0,
    "maxRepliesPerComment": 0,
    "proxyCountryCode": "None",
    "mcpMode": "perPost",
    "mcpMessage": """*@{{authorMeta.name}}* — {{diggCount}} likes · {{playCount}} views
{{text}}
{{webVideoUrl}}""",
    "mcpMaxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("harshmaur/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 '{
  "profiles": [
    "khaby.lame"
  ],
  "resultsPerPage": 10,
  "profileScrapeSections": [
    "videos"
  ],
  "maxFollowersPerProfile": 0,
  "maxFollowingPerProfile": 0,
  "commentsPerPost": 0,
  "maxRepliesPerComment": 0,
  "proxyCountryCode": "None",
  "mcpMode": "perPost",
  "mcpMessage": "*@{{authorMeta.name}}* — {{diggCount}} likes · {{playCount}} views\\n{{text}}\\n{{webVideoUrl}}",
  "mcpMaxItems": 50
}' |
apify call harshmaur/tiktok-scraper --silent --output-dataset

```

## MCP server setup

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