# TikTok Hashtag Scraper 🎵 Views, Posts & Top Videos (`gatherworks/tiktok-hashtag-scraper`) Actor

Track any TikTok hashtag by name. Total views, post count, views-per-post, and the videos ranking under it with likes, comments, shares and engagement. Paste hashtags, no IDs needed. Export to JSON, CSV or Excel. No login, no API key.

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

## Pricing

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

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## TikTok Hashtag Scraper 🎵 Views, Posts & Top Videos

**Track any TikTok hashtag by name and get the videos actually ranking under
it** — views, likes, shares, hashtags, music and a calculated engagement rate.
Switch on the **totals add-on** for the tag's own view and post counts.

**No account, no cookies, no API key.** Type a hashtag and run.

***

### 🔍 What is the TikTok Hashtag Scraper?

Give it hashtags the way you say them — `fitness`, `#fitness`, or a tag link.
No IDs to look up. For each one it returns:

- 🎬 the videos TikTok is currently ranking under it, with views, likes,
  comments, shares and a calculated engagement rate — this is the whole of a
  default run
- 🌏 rankings for the country you choose, because they differ by market
- 🏷️ **add-on, off by default** — the tag's own numbers: total views, total
  posts, and a views-per-post reach figure you can compare tags with, rather
  than a raw view count that only tells you how old the tag is

### ⚡ What can it do?

- **🏷️ Take hashtags by name.** Names, `#names`, and `tiktok.com/tag/…` links all
  resolve — you never need an internal ID.
- **📦 Track many tags at once** and compare them side by side.
- **🌏 Choose the region.** A tag ranks differently in the US than in the UK.
- **🔢 Filter by likes** to skip the long tail.
- **🚧 Cap how far a filter searches**, so a narrow filter stops rather than
  running away with your budget.
- **📄 Export anywhere.** JSON, CSV, Excel — the dataset is yours.

#### 🎯 Views per post, not just views *(totals add-on)*

A hashtag with a trillion views may simply be old. `viewsPerPost` divides total
views by total posts, which is the number that tells you whether posting under a
tag actually gets seen. It sits on the hashtag row, so a shortlist of tags sorts
itself — switch on **also return each hashtag's own totals** to get it.

### ⚡ Speed and accuracy

**Speed.** Measured on a real run: **1 hashtag and 15 videos in 6 seconds**.

**Accuracy.** Hashtag names are matched exactly where an exact match exists, so
`fitness` does not silently become `fitnessmotivation`. Videos are de-duplicated
by ID, so the same video is never returned or charged for twice. Counts are
numbers, not display text. Video links are canonical permalinks. Every video row carries the
hashtag it was found under, so a multi-tag run stays sortable.

### 📊 What data does it return?

**Video rows** (`rowType: "video"`) — the default output, returned on every run:

| Field | Notes |
|---|---|
| 🏷️ `hashtagName` | Which of your tags this video was found under |
| 🔗 `videoUrl` | Canonical permalink |
| 📝 `videoCaption` | The caption |
| 📊 `viewsCount`, `likesCount`, `commentsCount`, `sharesCount`, `savesCount` | Engagement |
| 📈 `engagementRate` | Engagement as a share of views |
| 🏷️ `authorHandle`, `authorDisplayName`, `authorIsVerified` | Who posted it |
| 🎵 `musicTitle` | The sound used |
| 📅 `publishedAt` | When it was posted, ISO 8601 |

**Hashtag rows** (`rowType: "hashtag"`) — the **add-on**, only when `includeHashtagRow` is
switched on:

| Field | Notes |
|---|---|
| 🏷️ `hashtagName`, `hashtagUrl` | The tag and a link to it |
| 📝 `hashtagDescription` | TikTok's own description, where there is one |
| 📊 `viewsCount`, `postsCount` | Total reach and total posts using it |
| 📈 `viewsPerPost` | Views divided by posts — comparable across tags |
| 🚩 `isCommerce` | Whether TikTok marks it as a commerce tag |

#### 🚫 What it does **not** return

- **Every video ever posted under a tag.** You get what TikTok ranks, which is
  what a person browsing the tag would see.
- **Historical view counts.** The figure is the total as of the run.
- **Videos from private accounts.**

### 💰 How much does it cost?

You pay per event, for what the run actually produces — never for runtime, and
never on a subscription.

Standard rate: **💵 $0.0022 per video**. The hashtag's own totals are an add-on
at **💵 $0.0170**, and are off unless you switch them on:

| Run | Cost |
|---|---|
| 🟩 5 hashtags, 50 videos each *(the default run)* | 💵 $0.55 |
| 🟨 20 hashtags, 100 videos each | 💵 $4.40 |
| 🟧 20 hashtags, 100 videos each **+ the totals add-on** | 💵 $4.74 |

**A hashtag that does not resolve is free.** So is a video your filters remove.
**A month you do not run it costs nothing at all** — there is no plan to keep alive.

#### What you get for that

| | Included here |
|---|---|
| 📈 Views per post, computed | ✅ with the totals add-on |
| 🏷️ Hashtags accepted by name, not ID | ✅ |
| 🌏 Region-specific rankings | ✅ free |
| 🎵 Creator, sound and caption on every video | ✅ free |
| 🔎 Like filter | ✅ free |
| 💳 Minimum spend | none |

### 🚀 How do I use it?

1. Type one or more **hashtags**.
2. Leave **include the videos ranking under each hashtag** on — that is the
   default run.
3. Set the **region** whose rankings you want.
4. Set **maximum videos per hashtag** to control cost.
5. Optionally switch on **#️⃣ also return each hashtag's own totals** — the
   **add-on**, off by default — for one extra row per tag carrying its view and
   post counts. Switching *both* of these off is refused: the run would return
   nothing.
6. Run, then sort videos by `engagementRate` (and, with the add-on on, tags by
   `viewsPerPost`).

### ⚙️ Input

| Field | Notes |
|---|---|
| 🏷️ `hashtags` | Names, #names or tag links |
| 🎬 `includeVideos` | Collect the videos ranking under each tag — on by default |
| #️⃣ `includeHashtagRow` | Also return each hashtag's own totals. **Add-on — off by default** |
| 🔢 `maxVideosPerHashtag` | How many videos to return per tag — default `50` |
| 🌏 `region` | Two-letter country code for the rankings — default `US` |
| 🔢 `minLikes` | Keep only videos above this like count — no minimum by default |
| 🚧 `maxScanned` | How many videos a like filter may skip before stopping — default `500` |

`includeVideos` and `includeHashtagRow` cannot both be off — a run with nothing
switched on stops with a message rather than burning your budget on nothing.

```json
{
  "hashtags": ["fitness", "#skincare"],
  "includeVideos": true,
  "includeHashtagRow": false,
  "maxVideosPerHashtag": 50,
  "region": "US"
}
```

### 📄 Output example

A real video row — what a default run returns, captured from a live run:

```json
{
  "rowType": "video",
  "hashtagName": "Fitness",
  "videoUrl": "https://www.tiktok.com/@nayaafitt/video/7668655133747580182",
  "publishedAt": "2026-07-31T11:38:35.000Z",
  "viewsCount": 3016051,
  "likesCount": 360708,
  "commentsCount": 903,
  "authorHandle": "nayaafitt"
}
```

With the **totals add-on** on, each tag also gets a row of its own:

```json
{
  "rowType": "hashtag",
  "hashtagName": "Fitness",
  "viewsCount": 794216826811,
  "postsCount": 66398886,
  "viewsPerPost": 11961,
  "hashtagUrl": "https://www.tiktok.com/tag/Fitness"
}
```

### ❓ Frequently asked questions

**Do I need a TikTok account?** No. No account, no cookies, no API key.

**Do I need the hashtag's ID?** No. Type the name and it is resolved for you.

**Why does the same tag give different videos in different regions?** Because
TikTok ranks tags per market. Set `region` to the country you care about.

**What is `viewsPerPost` for?** Comparing tags. A huge view count can just mean a
tag is old; views per post tells you what a new post might actually get. It
arrives on the hashtag row, so switch on the **totals add-on** to get it.

**Can I get every video under a tag?** No — you get what TikTok ranks, which is
what a person browsing the tag would see.

### 🏷️ Pricing

Pay per event — you are charged for output, not for platform time.

| Event | Price | Covers |
|---|---|---|
| 🎬 `video` — **primary** | 💵 $0.0022 | One video ranking under a hashtag. **The only charge a default run makes** |
| #️⃣ `hashtag` — **add-on** | 💵 $0.0170 | A row with the hashtag’s own view and post totals. Only when `includeHashtagRow` is on |
| ▶️ `apify-actor-start` | 💵 $0.00005 | Starting one run, charged once per GB of memory |
| 📊 Views, likes and engagement rate | ✅ **free** | On every video row |
| 🔎 Filtering and the scan cap | ✅ **free** | Videos your filter removes are not charged for, and neither are duplicates |
| ❌ Hashtags that do not resolve | ✅ **free** | Reported, never charged |

**The add-on is off by default.** Leave it off and you are charged the
`video` rate and nothing else — the price on the card is the price of the run.

#### 🏅 Rates by tier

The prices above are the standard rate. Higher Apify plans are billed at the
discounted tiers below, automatically:

| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| 🎬 `video` | 💵 $0.0022 | 💵 $0.0019 | 💵 $0.0016 | 💵 $0.0013 |
| #️⃣ `hashtag` | 💵 $0.0170 | 💵 $0.0147 | 💵 $0.0123 | 💵 $0.0100 |
| ▶️ `apify-actor-start` | 💵 $0.00005 | 💵 $0.00005 | 💵 $0.00005 | 💵 $0.00005 |

#### 🛑 You are never billed past your limit

Set a maximum charge on the run and the Actor stops when it reaches it, with
every hashtag collected up to that point complete and saved. Filtered-out videos
are never stored and never billed.

# Actor input Schema

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

Hashtags by name — <code>fitness</code>, <code>#fitness</code> and a full <code>tiktok.com/tag/…</code> link all work. No IDs needed.

## `includeVideos` (type: `boolean`):

Collect the videos TikTok surfaces for the tag. On by default — this is what most runs are for.

## `includeHashtagRow` (type: `boolean`):

Adds one row per hashtag carrying its total view and post counts. <b>Off by default</b>: the ranked videos are what most runs are for. Billed as an add-on when switched on.

## `maxVideosPerHashtag` (type: `integer`):

Caps how many videos are returned for each hashtag. Cost scales linearly with this number.

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

Two-letter country code the rankings are read for, for example <code>US</code>, <code>GB</code>, <code>AU</code>. Hashtag rankings differ by country.

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

Keep only videos with at least this many likes. Leave empty for no minimum.

## `maxScanned` (type: `integer`):

Only applies when a minimum like count is set. Caps how many videos the filter may reject before the Actor stops and returns what it found, so a narrow filter cannot walk an entire hashtag. Videos it keeps do not count towards this, and the effective limit is never more than ten times the videos-per-hashtag limit.

## Actor input object example

```json
{
  "hashtags": [
    "fitness",
    "#skincare"
  ],
  "includeVideos": true,
  "includeHashtagRow": false,
  "maxVideosPerHashtag": 50,
  "region": "US",
  "maxScanned": 500
}
```

# Actor output Schema

## `hashtags` (type: `string`):

One row per video ranking under each hashtag - the default output - plus an optional row carrying each tag's own view and post totals when the add-on is switched on.

# 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": [
        "fitness",
        "#skincare"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gatherworks/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": [
        "fitness",
        "#skincare",
    ] }

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

```

## MCP server setup

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