# TikTok Scraper - Videos, Profiles, Comments & Hashtags (`briskpebble/tiktok-scraper`) Actor

Scrape TikTok videos, profiles, comments, hashtags, sounds and search results. Get plays, likes, shares, captions, followers and subtitles, and download videos. Free date and popularity filters, no login or API key. Export to JSON, CSV or Excel. Pay only for results.

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

## Pricing

from $1.20 / 1,000 video scrapeds

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

### What does TikTok Scraper do?

**TikTok Scraper** extracts public data from [TikTok](https://www.tiktok.com): **videos, profiles, comments and replies, hashtags, sounds and search results**. Start from any mix of:

- \#️⃣ **Hashtags**: the videos TikTok lists for `#cooking`, `#fyp` or any other tag
- 😎 **Profiles**: profile details (followers, likes, bio, emails in the bio) plus posted videos and reposts
- 🔍 **Search**: Top results, video results, or creators matching a keyword
- 🔗 **Any TikTok URL**: videos, photo posts, `vm.tiktok.com` short links, and profile, hashtag, sound and search pages
- 🎵 **Sounds**: the videos that use a sound or song

You don't need a TikTok account, API key or login. Results land in a clean dataset you can download as **JSON, CSV, Excel, XML or HTML**, call through the **Apify API**, schedule, or connect to **Make, Zapier, n8n, Google Sheets, Slack** and AI agents over **MCP**.

### Why use this TikTok scraper?

- **Drop-in compatible.** Input fields and output fields match the most popular TikTok scraper on Apify (`hashtags`, `profiles`, `resultsPerPage`, `postURLs`, `authorMeta`, `videoMeta`, `diggCount`, …). Switch by changing the Actor ID; your integrations keep working.
- **Built for TikTok in 2026.** TikTok signs every web API call with tokens (`X-Bogus`, `X-Gnarly`, …) that change often, which breaks most scrapers. This Actor lets TikTok's own code in a real browser sign the requests, and reads pages over plain HTTP whenever possible, so runs stay fast and cheap.
- **Filters are free.** Date range, minimum and maximum likes, minimum plays and pinned-post filters cost nothing extra, and filtered-out videos are never charged. On profiles the scraper stops paginating once it passes your date.
- **Exact numbers.** Likes, plays, shares, saves and followers come from TikTok's exact counters, not rounded values like "1.3M".
- **Comments with replies.** Every comment has its author, text, likes and reply count; replies point to their parent comment.
- **Media downloads.** Optionally save MP4 files, thumbnails, slideshow images, avatars and subtitles to a key-value store.
- **Reliable runs.** Flagged sessions are replaced automatically, duplicates are removed across inputs, the run resumes after a platform migration without charging twice, and it fails loudly instead of returning an empty "success".

### What TikTok data can I extract?

| Videos | Profiles | Comments |
| --- | --- | --- |
| Caption, language, URL, created date | Username, display name, profile URL | Comment text and ID |
| Plays, likes, shares, saves, comments, reposts | Followers, following, total likes, video count | Likes and reply count |
| Author (with follower and like counts) | Bio, bio link, **emails found in the bio** | Commenter username, name, avatar |
| Sound: name, author, album, original, URL | Verified, private, TikTok Shop seller | Reply flag and parent comment ID |
| Duration, size, resolution, codec, cover and video URLs | Business category, language, region | Liked or pinned by the creator |
| Hashtags, mentions, effects, on-screen text | Account creation date | Video ID and URL |
| Slideshow images, subtitles, posting country | Avatar (and downloaded copy) | Created date |
| Ad, paid partnership, pinned, AI-generated flags | | |

Every item has a `dataType` (`video`, `profile` or `comment`), the `input` it came from and a `source` object, so you can group results by input.

### How to scrape TikTok

1. Click **Try for free** and open the **Input** tab.
2. Add at least one target: a hashtag like `cooking`, a username like `nasa`, a search query, a TikTok URL or a sound.
3. Set **💯 Number of videos** (per hashtag, profile, search or sound).
4. Optional: add **date and popularity filters**, **comments**, **media downloads**, or pick a **country** to scrape as if you were there.
5. Click **Start**, then download your data from the **Output** tab, or use the API.

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

This Actor uses **pay-per-event** pricing: you pay a small fee per **video**, **profile** and **comment** saved, per **video file downloaded**, plus a tiny start fee per run. Current prices are on the **Pricing** tab, and higher Apify plans get automatic discounts. Filters, the country option, subtitles, thumbnails and avatars cost nothing extra.

**Maximum results** and the run's maximum cost cap your spending exactly; the run stops as soon as either is reached. With the Apify **free plan's** monthly credit you can try the scraper on a few thousand videos at no cost.

### Input example

```json
{
    "hashtags": ["cooking"],
    "profiles": ["nasa"],
    "searchQueries": ["pasta recipe"],
    "searchSection": "/video",
    "postURLs": ["https://www.tiktok.com/@nasa/video/7697300954667994381"],
    "resultsPerPage": 50,
    "oldestPostDateUnified": "30 days",
    "leastDiggs": 1000,
    "commentsPerPost": 20,
    "maxRepliesPerComment": 3,
    "shouldDownloadCovers": true,
    "proxyCountryCode": "US",
    "maxItems": 2000
}
```

### Output example

A video (shortened):

```json
{
    "dataType": "video",
    "id": "7686212146052549902",
    "text": "s’mores cookie bars 🐻🍫🤎 #smores #smorescookies #cookiebars #baking #dessert",
    "textLanguage": "en",
    "createTimeISO": "2026-09-21T14:13:20.000Z",
    "webVideoUrl": "https://www.tiktok.com/@gisellecooks_/video/7686212146052549902",
    "playCount": 11900000,
    "diggCount": 1300000,
    "shareCount": 306200,
    "commentCount": 3636,
    "collectCount": 404316,
    "authorMeta": { "name": "gisellecooks_", "nickName": "Giselle", "verified": false, "fans": 1500000, "profileUrl": "https://www.tiktok.com/@gisellecooks_" },
    "musicMeta": { "musicId": "7603351654578210832", "musicName": "Venus and Flower", "musicAuthor": "Austin Farwell", "musicOriginal": false },
    "videoMeta": { "duration": 60, "width": 720, "height": 1280, "definition": "720p", "format": "mp4", "coverUrl": "https://p16-common-sign.tiktokcdn-us.com/..." },
    "hashtags": [{ "id": "7250", "name": "baking", "title": null, "cover": null }],
    "isAd": false,
    "isPinned": false,
    "isSlideshow": false,
    "searchHashtag": { "name": "cooking", "views": 107086172719, "videos": 6026846 },
    "input": "cooking",
    "source": { "type": "hashtag", "input": "cooking" },
    "scrapedAt": "2026-10-19T17:49:20.496Z"
}
```

A profile:

```json
{
    "dataType": "profile",
    "id": "7664638705177150477",
    "name": "nasa",
    "nickName": "NASA",
    "profileUrl": "https://www.tiktok.com/@nasa",
    "verified": true,
    "signature": "Making the seemingly impossible, possible.✨",
    "bioLink": "https://science.nasa.gov/feature/artemis-ii-preliminary-lunar-science-report",
    "emails": [],
    "fans": 2107037,
    "following": 23,
    "heart": 11198124,
    "video": 57,
    "input": "nasa",
    "source": { "type": "profile", "input": "nasa" }
}
```

A comment:

```json
{
    "dataType": "comment",
    "cid": "7698165061331927838",
    "text": "the apple in space has me emotional",
    "diggCount": 0,
    "replyCommentTotal": 0,
    "isReply": false,
    "repliesToId": null,
    "uniqueId": "addisonbaddison420",
    "createTimeISO": "2026-10-19T00:12:31.000Z",
    "videoId": "7694813092256959774",
    "videoWebUrl": "https://www.tiktok.com/@google/photo/7694813092256959774"
}
```

The **Output** tab has ready-made **Videos**, **Profiles** and **Comments** tables.

### Tips for the best results

- **Keep the residential proxy** (the default). TikTok blocks most datacenter IPs.
- **Use the country option** to see what TikTok shows in a given market; trends and availability differ per country.
- **Profiles:** since 2026 TikTok shows logged-out visitors only the newest videos of many profiles. When that happens the scraper saves the ~10 newest videos from the creator's embed, tells you in the log, and still saves the profile item. To collect more of a creator's videos, add hashtags or search queries they use.
- **Monitoring:** schedule a daily run with `oldestPostDateUnified: "1"` to collect only today's videos.
- **Speed vs. blocking:** 2–5 **parallel browser sessions** work well. More sessions are faster but more likely to be rate-limited.

### Integrations and API

Run the Actor from your code with the [Apify API](https://docs.apify.com/api/v2) or the Apify clients for [JavaScript](https://docs.apify.com/api/client/js) and [Python](https://docs.apify.com/api/client/python):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<YOUR_USERNAME>/tiktok-scraper").call(run_input={
    "hashtags": ["cooking"],
    "resultsPerPage": 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["webVideoUrl"], item["diggCount"])
```

You can also connect it to Make, Zapier, n8n, Google Sheets, Airbyte, Slack, webhooks, and AI agents through the [Apify MCP server](https://mcp.apify.com).

### FAQ

#### Is it legal to scrape TikTok?

This Actor collects only publicly visible data and doesn't log in. Scraping public data is generally legal, but personal data is protected by regulations such as the GDPR, and TikTok's terms restrict automated access. Make sure you have a legitimate reason to collect the data, and ask a lawyer if you're unsure. Read more in [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

#### Do I need a TikTok account or API key?

No. The Actor works without login, cookies or TikTok's restricted Research API.

#### Why did I get fewer videos than "Number of videos"?

TikTok stops serving results for some lists (for example, very deep hashtag pages), your filters may have removed videos, a profile may hide its video list from logged-out visitors (see Tips), or the run reached **Maximum results** or your maximum cost. The log explains which one.

#### Can I download the videos?

Yes. Turn on **Download video files**. Files go to the run's key-value store (or the named store you choose) and each video item gets a `videoMeta.downloadedVideoUrl` link. Thumbnails, slideshow images, avatars and subtitles can be downloaded too.

#### Does it get video transcripts?

It downloads the subtitles TikTok has for a video (auto-generated captions or the creator's own) and includes their text. Videos without subtitles are not transcribed.

#### Something broke. What should I do?

Run again with **Debug logging** on and open an issue on the **Issues** tab with the run link. TikTok changes often; fixes usually ship within a day or two.

# Changelog

This Actor's version history is a separate document: https://apify.com/briskpebble/tiktok-scraper/changelog.md

# Actor input Schema

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

One or more hashtags, with or without the #. The scraper collects the videos TikTok lists for each hashtag: text, likes, plays, shares, author, sound and more. Use <strong>Bulk edit</strong> to paste a list.

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

How many videos to save for each hashtag, profile section, search query, sound and video's related list. The run stops paginating an input as soon as this many videos pass your filters.

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

TikTok usernames or profile URLs, e.g. <code>nasa</code>, <code>@nasa</code> or <code>https://www.tiktok.com/@nasa</code>. You get one profile item (followers, likes, bio, emails found in the bio) plus the profile's videos.<br><br><strong>Note:</strong> since 2026 TikTok shows logged-out visitors only the newest videos of many profiles. When the full list is hidden, the scraper falls back to the creator embed (about 10 newest videos) and says so in the log.

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

Videos the profile posted, videos it reposted, or both. Each section gets its own <strong>Number of videos</strong> limit.

## `includeProfileDetails` (type: `boolean`):

Save one item per profile (dataType "profile") with follower, following, likes and video counts, bio, bio link, emails found in the bio, verified and seller flags. Turn off if you only want the videos.

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

Skip videos the creator pinned to the top of the profile.

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

Keywords to search on TikTok, one per line. Any query that works in the TikTok search box works here.

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

<strong>Top</strong> returns the videos in TikTok's Top results, <strong>Video</strong> searches videos only, <strong>Profile</strong> returns creators (one profile item each, up to <strong>Number of profiles per query</strong>).

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

Only for the Profile section: how many creators to save per search query.

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

Keep only search results posted within this period. Applied to every result, so it is exact.

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

Video and photo URLs (<code>https://www.tiktok.com/@user/video/123...</code>), short links (<code>vm.tiktok.com/...</code>), and profile, hashtag, sound and search URLs. Each video URL returns the full video item.

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

For each video URL above, also save the videos TikTok recommends next to it (up to <strong>Number of videos</strong> per video).

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

Sound URLs (<code>https://www.tiktok.com/music/name-7016547803243022337</code>) or sound IDs. Collects the videos that use each sound.

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

A date (<code>2026-01-31</code>), a relative time (<code>7 days</code>, <code>2 weeks</code>) or a number of days: <code>1</code> = today only, <code>2</code> = yesterday and today. On profiles, the scraper stops paginating once it reaches older videos. Free, unlike some other scrapers.

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

A date (<code>2026-01-31</code> includes the whole day) or a relative time like <code>1 day</code>.

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

Keep only videos with at least this many likes.

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

Keep only videos with fewer likes than this, e.g. to find smaller creators.

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

Keep only videos played at least this many times.

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

Save up to this many top-level comments for every scraped video, as separate items (dataType "comment") with text, likes, author and reply count. 0 = no comments.

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

Also save up to this many replies for each saved comment that has replies. Replies have <code>isReply: true</code> and <code>repliesToId</code> set to the parent comment.

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

Save each video's MP4 file to the key-value store and add its link as <code>videoMeta.downloadedVideoUrl</code>. Charged per downloaded file.

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

Save video cover images (<code>videoMeta.downloadedCoverUrl</code>).

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

Save every image of photo posts (<code>slideshowImageLinks\[].downloadLink</code>).

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

Save authors' profile pictures (<code>authorMeta.downloadedAvatarUrl</code>).

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

Download the subtitles TikTok has for a video (auto-generated captions or the creator's own) as WebVTT, and include their text in <code>videoMeta.subtitleLinks\[].text</code>. Not every video has subtitles.

## `videoKvStoreIdOrName` (type: `string`):

Name of the key-value store for downloaded files. Leave empty to use the run's default store, which is deleted after your plan's data retention period; a named store keeps the files until you delete it. Letters, digits and hyphens only.

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

Total number of items (videos + profiles + comments) to save across all inputs. The run stops when it is reached, which caps the cost of a run.

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

TikTok shows different videos, trends and availability per country. Pick a country to route the residential proxy through it. No extra charge.

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

TikTok blocks most datacenter IPs, so residential proxies are the default and strongly recommended.

## `maxConcurrency` (type: `integer`):

How many TikTok sessions run in parallel, each with its own IP. More is faster but more likely to be rate-limited; 2–5 works well.

## `debugLog` (type: `boolean`):

Log every request and decision. Useful when reporting an issue.

## Actor input object example

```json
{
  "hashtags": [
    "cooking"
  ],
  "resultsPerPage": 20,
  "profileScrapeSections": [
    "videos"
  ],
  "includeProfileDetails": true,
  "excludePinnedPosts": false,
  "searchSection": "",
  "maxProfilesPerQuery": 10,
  "videoSearchDateFilter": "ALL_TIME",
  "scrapeRelatedVideos": false,
  "commentsPerPost": 0,
  "maxRepliesPerComment": 0,
  "shouldDownloadVideos": false,
  "shouldDownloadCovers": false,
  "shouldDownloadSlideshowImages": false,
  "shouldDownloadAvatars": false,
  "downloadSubtitlesOptions": "NEVER_DOWNLOAD_SUBTITLES",
  "maxItems": 1000,
  "proxyCountryCode": "None",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 3,
  "debugLog": false
}
```

# Actor output Schema

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

Every scraped video, profile and comment in one dataset. Each item has a dataType field: video, profile or comment.

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

Videos with caption, author, plays, likes, comments, shares, saves, sound and link.

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

Profiles with followers, likes, video count, bio, bio link and emails found in the bio.

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

Comments and replies with author, text, likes and the video they belong to.

## `files` (type: `string`):

Video files, thumbnails, slideshow images, avatars and subtitles, when downloads are on (and no named store was chosen).

# 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 = {
    "hashtags": [
        "cooking"
    ],
    "resultsPerPage": 20,
    "commentsPerPost": 0,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("briskpebble/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 = {
    "hashtags": ["cooking"],
    "resultsPerPage": 20,
    "commentsPerPost": 0,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("briskpebble/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 '{
  "hashtags": [
    "cooking"
  ],
  "resultsPerPage": 20,
  "commentsPerPost": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call briskpebble/tiktok-scraper --silent --output-dataset

```

## MCP server setup

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