# TikTok Hashtag Scraper (`calm_builder/tiktok-hashtag-scraper`) Actor

Scrape TikTok hashtag videos in depth: 800-1,200+ per popular tag. Get views, likes, comments, shares, saves, caption, author, music and video link, plus optional comments and subtitles. Free date filters and sorting.

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

## Pricing

from $0.80 / 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

## TikTok Hashtag Scraper

Scrape the videos of any TikTok hashtag as clean, structured data, with far more videos per hashtag than one TikTok feed shows.

Add hashtags, choose how many videos you need from each, and export the results as JSON, CSV or Excel, or pull them through the Apify API. Results appear in your dataset while the run is still going.

### What This Actor Does

- Collects the **videos of each hashtag** with views, likes, comments, shares, saves, caption, hashtags, mentions, music, cover image, video link and subtitle links, plus the author's full profile
- **Deep results**: popular hashtags typically give **800 to 1,200+ unique videos**, far more than you can scroll on TikTok's hashtag page
- Collects each video's **comments and replies** with one switch, in their own table
- **Date filters, view and like filters, sorting, subtitles and country selection are included at no extra cost**

### Best For

- Trend research and content ideas
- Finding creators who post about a topic
- Brand, campaign and challenge monitoring
- Collecting comments under a hashtag for sentiment analysis
- Building datasets for dashboards, BI or AI workflows

### Input

| Field                     | What it does                                                                                              |
| ------------------------- | --------------------------------------------------------------------------------------------------------- |
| `hashtags`                | Hashtags, with or without `#`, e.g. `gymtok`, `#booktok`                                                  |
| `startUrls`               | Hashtag links, e.g. `https://www.tiktok.com/tag/booktok`                                                  |
| `resultsPerPage`          | How many videos to collect from each hashtag (default 100)                                                |
| `newerThan` / `olderThan` | Only videos from a date range. Accepts a date (`2026-06-01`) or a relative period (`7 days`, `3 months`) |
| `minViews` / `minLikes`   | Only videos above a popularity threshold                                                                 |
| `sortBy`                  | `default`, `newest`, `oldest`, `mostViewed`, `mostLiked`, `mostShared`                                    |
| `includeComments`         | Also collect the comments of every video (paid add-on)                                                    |
| `maxCommentsPerVideo`     | How many comments per video                                                                               |
| `includeReplies`          | Also collect replies to comments (charged as comments)                                                    |
| `includeSubtitles`        | Add the subtitle text of each video                                                                       |
| `country`                 | Show videos as TikTok ranks them in this country first (default United States)                           |

#### Example input

```json
{
  "hashtags": ["gymtok", "#booktok"],
  "resultsPerPage": 500,
  "newerThan": "3 months",
  "sortBy": "mostViewed"
}
```

### Output

Each run has two tables, both on the run's **Output** tab:

- **Videos** (main table): one row per video or photo post. `source` shows which hashtag each video came from.
- **Comments & replies**: filled only when **Include comments** is on. Every row carries `videoId`, `videoUrl`, `videoAuthor` and `videoCaption`, so it links back to its video.

Every field is included when you export or use the API.

#### Video fields

| Field                                                                               | Description                                                       |
| ----------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `id`, `url`                                                                         | Video ID and link                                                 |
| `text`, `language`                                                                  | Caption and its language                                          |
| `createdAt`                                                                         | Upload time (ISO 8601)                                            |
| `viewCount`, `likeCount`, `commentCount`, `shareCount`, `saveCount`, `repostCount`  | Engagement                                                        |
| `durationSeconds`, `width`, `height`, `definition`, `format`                        | Video details                                                     |
| `coverUrl`, `originalCoverUrl`, `videoUrl`, `downloadUrl`, `images`                 | Cover, video file links, and all images of a photo post          |
| `isPinned`, `isPhotoPost`, `isAd`, `isSponsored`, `isAiGenerated`, `hasShopProduct` | Flags                                                             |
| `hashtags`, `hashtagDetails`, `mentions`, `mentionedUsers`, `effects`               | Hashtags (with IDs), mentioned users (with IDs) and effects used  |
| `location`                                                                          | The tagged place, when there is one                               |
| `music`                                                                             | Sound ID, title, author, album, original-sound flag, cover, links |
| `hasSubtitles`, `subtitleLinks`, `subtitles`                                        | Subtitle availability, links per language, and text when enabled  |
| `author`                                                                            | The creator's full profile: username, name, bio, followers, likes |
| `source`                                                                            | The hashtag the video came from                                   |

#### Example output

A video row (author shortened):

```json
{
  "type": "video",
  "id": "7111798235991264558",
  "url": "https://www.tiktok.com/@bellaanya/video/7111798235991264558",
  "text": "For my gym anxiety gals #fyp #workout #squats #squat #squatrack #squatracktips #greenscreenvideo #greenscreen #gymgirls #gymtok",
  "createdAt": "2022-06-21T20:49:22Z",
  "viewCount": 9000000,
  "likeCount": 1100000,
  "commentCount": 1010,
  "shareCount": 1114,
  "saveCount": 73131,
  "durationSeconds": 42,
  "hashtags": [
    "fyp",
    "workout",
    "squats",
    "squat",
    "squatrack",
    "squatracktips",
    "greenscreenvideo",
    "greenscreen",
    "gymgirls",
    "gymtok"
  ],
  "music": {
    "title": "original sound",
    "authorName": null
  },
  "author": {
    "username": "bellaanya",
    "followerCount": 319800,
    "verified": false
  },
  "source": {
    "type": "hashtag",
    "value": "gymtok"
  }
}
```

### How To Use

1. Add one or more hashtags.
2. Set **Maximum videos per hashtag**.
3. Optionally add date or popularity filters, a sort order, or comments.
4. Run the Actor and open the **Output** tab, export the results, or read them through the Apify API.

### Pricing

This Actor uses pay-per-event pricing, so you only pay for results you receive:

- **Video**: each video or photo post saved to your dataset
- **Comment**: each comment or reply saved, only when you turn comments on
- **Actor start**: a small fee each time a run starts

Filters, sorting, subtitles and country selection are **included at no extra cost**, and you are charged only for videos that pass your filters. Current prices for each Apify plan are shown on the Actor's Pricing tab.

If a run reaches the maximum cost you set for it, it stops cleanly and keeps everything collected so far.

#### Free plan

On the Apify free plan every feature is available to try, with smaller amounts per run: up to **3** hashtags, **10** videos per hashtag, **10** comments per video and **3** replies per comment. Upgrade to a paid Apify plan to remove these limits.

### Best Practices

- Start with a small **Maximum videos per hashtag** to check the output quickly.
- For monitoring, use **Only videos newer than** (for example `7 days`) on a schedule.
- Use **Most viewed** sorting to get the top videos of the videos collected.

### FAQ

#### How many videos can I get from one hashtag?

Typically 800 to 1,200+ unique videos for a popular hashtag, and fewer for small ones. Every video is saved once, without duplicates.

#### Why did a hashtag return fewer videos than I asked for?

The hashtag may be small, or fewer videos matched your date or popularity filters. The run log tells you when that happens.

#### Why are some videos missing the exact hashtag in their caption?

TikTok's own hashtag page also shows closely related videos. This Actor returns exactly what TikTok shows for the hashtag.

#### How long does a run take?

Most runs finish in under a minute: three hashtags with 600 videos each took about 65 seconds in our tests.

### Responsible Use

This Actor collects publicly available data only. Make sure your use complies with TikTok's terms, applicable laws and data-protection rules such as the GDPR, especially when you process personal data.

### Troubleshooting

- **A hashtag could not be found**: check the spelling. Hashtags have no spaces.
- **No videos from a hashtag**: the hashtag may be empty or blocked by TikTok, or nothing matched your filters.
- **A link was skipped**: this Actor accepts hashtag links only. Use the TikTok Scraper for profiles, videos and search.

If something still does not work, open an issue on the Actor's Issues tab with your run link and we will take a look.

# Actor input Schema

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

Hashtags to collect videos from, one per row, with or without the `#`.

Examples: `gymtok`, `#booktok`, `airfryerrecipes`.

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

TikTok hashtag page links, one per row, e.g. `https://www.tiktok.com/tag/booktok`. Other kinds of links are skipped.

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

How many videos to collect from **each** hashtag.

Popular hashtags typically give 800-1,200+ unique videos; small hashtags end sooner.

## `newerThan` (type: `string`):

Skip videos posted before this date. Pick a date, or enter a relative period such as `7 days` or `3 months`.

## `olderThan` (type: `string`):

Skip videos posted after this date. Combine with **Only videos newer than** to collect a specific period.

## `minViews` (type: `integer`):

Only return videos with at least this many views. Leave empty to keep all videos.

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

Only return videos with at least this many likes. Leave empty to keep all videos.

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

Order of the videos collected from each hashtag.

- **Default** — the order TikTok shows them in
- **Newest first** / **Oldest first** — by upload date
- **Most viewed** / **Most liked** / **Most shared** — by engagement

Sorting applies to the videos collected from each hashtag, up to your **Maximum videos per hashtag**.

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

Collect the comments of every video in the run. They are saved in the **Comments & replies** table, one row each, linked to their video through `videoId`.

Comments are an optional add-on with their own price. Comment order and comment filters below are included at no extra cost.

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

How many top-level comments to collect from each video.

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

Also collect replies to each comment.

Requires **Include comments**. Each reply is charged as a comment.

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

How many replies to collect under each comment.

## `commentLayout` (type: `string`):

How comments are saved in the **Comments & replies** table.

- **One row each** — every comment and every reply is its own row, with `type` and `parentCommentId`; best for spreadsheets
- **Replies nested** — one row per comment, with its replies inside the `replies` field; best for JSON and code

Every row carries `videoId`, `videoUrl`, `videoAuthor` and `videoCaption`. Pricing is the same either way.

## `commentSort` (type: `string`):

Which comments to collect first.

- **TikTok's order** — the order the TikTok app shows (fastest)
- **Most liked** — the most-liked comments of each video
- **Newest** — the most recent comments of each video

**Most liked** and **Newest** read up to 1,000 comments per video to pick from, so they take a few seconds longer per video. You are charged only for the comments returned.

## `commentsNewerThan` (type: `string`):

Skip comments posted before this date. Pick a date, or enter a relative period such as `24 hours` or `7 days`. Ideal for monitoring.

## `minCommentLikes` (type: `integer`):

Only return comments with at least this many likes. Leave empty to keep all.

## `commentKeywords` (type: `array`):

Only return comments containing at least one of these words or phrases (not case-sensitive), e.g. `price`, `where to buy`. Leave empty to keep all.

## `includeSubtitles` (type: `boolean`):

Add the full subtitle text of each video in the `subtitles` field, in every language TikTok provides. Included at no extra cost.

Only videos that have subtitles on TikTok (including auto-generated captions) return them.

## `country` (type: `string`):

Videos are shown as TikTok ranks them in this country first. Included at no extra cost.

## Actor input object example

```json
{
  "hashtags": [
    "gymtok"
  ],
  "resultsPerPage": 100,
  "sortBy": "default",
  "includeComments": false,
  "maxCommentsPerVideo": 20,
  "includeReplies": false,
  "maxRepliesPerComment": 10,
  "commentLayout": "rows",
  "commentSort": "default",
  "includeSubtitles": false,
  "country": "US"
}
```

# Actor output Schema

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

No description

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

No description

# 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": [
        "gymtok"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("calm_builder/tiktok-hashtag-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": ["gymtok"] }

# Run the Actor and wait for it to finish
run = client.actor("calm_builder/tiktok-hashtag-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": [
    "gymtok"
  ]
}' |
apify call calm_builder/tiktok-hashtag-scraper --silent --output-dataset

```

## MCP server setup

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