# TikTok Hashtag Stats (`funny_ground/tiktok-hashtag-stats`) Actor

Scrapes TikTok hashtag summary data (exact video count & view count) using Playwright to intercept the /api/challenge/detail XHR. No login required.

- **URL**: https://apify.com/funny\_ground/tiktok-hashtag-stats.md
- **Developed by:** [Coor Yu](https://apify.com/funny_ground) (community)
- **Categories:** Social media, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Stats Actor

> **Language / 语言**: [English](#english) · [中文](#中文)

---

### English

#### What it does

Scrapes **exact** TikTok hashtag-level summary statistics — video count and total view count — using Playwright.

The actor opens `https://www.tiktok.com/tag/<hashtag>` in a headless Chromium browser and intercepts the `/api/challenge/detail` XHR that TikTok fires automatically on page load.  This XHR carries `challengeInfo.statsV2.videoCount` and `statsV2.viewCount` as exact integers (e.g. `1 403 431 633 800`), far more precise than the abbreviated text shown on-screen ("1.4T views").

#### How it works

````

Browser opens https://www.tiktok.com/tag/<hashtag>
│
├─► Path 1 (primary)
│   XHR /api/challenge/detail intercepted
│   └─ statsV2.videoCount  ← exact integer  ✓
│   └─ statsV2.viewCount   ← exact integer  ✓
│
├─► Path 2 (DOM fallback — XHR not triggered)
│   Read visible page text:
│   \[data-e2e="challenge-vvcount"]    → view\_count  (e.g. "1.4T views")
│   \[data-e2e="challenge-item-count"] → video\_count (e.g. "100M videos")
│   Values are approximate (K/M/B/T rounded)
│
└─► Path 3 (failure)
CAPTCHA or network error — error field is set

````

#### Output fields

| Field | Type | Description |
|---|---|---|
| `hashtag` | string | Canonical hashtag name from TikTok |
| `platform` | string | Always `"tiktok"` |
| `challenge_id` | string | TikTok internal challenge ID |
| `video_count` | integer\|null | Total number of videos |
| `view_count` | integer\|null | Total cumulative view count |
| `description` | string | Hashtag description text |
| `is_commerce_hashtag` | bool | Whether it is a commerce/branded hashtag |
| `share_meta_desc` | string | Short share description |
| `_source` | string | Code path that produced the result |
| `error` | string\|null | Non-null only on failure |

#### Example output

```json
{
  "hashtag": "roblox",
  "challenge_id": "159721",
  "platform": "tiktok",
  "video_count": 100049186,
  "view_count": 1403431633800,
  "description": "Explore and find your own favourite way to play with #Roblox!",
  "is_commerce_hashtag": false,
  "share_meta_desc": "Watch awesome short videos created with trending hashtag #roblox",
  "_source": "Playwright /api/challenge/detail statsV2"
}
````

#### Input

| Field | Required | Default | Description |
|---|---|---|---|
| `hashtags` | Yes | – | Array of hashtag names (without `#`), e.g. `["roblox", "minecraft"]` |
| `proxyConfiguration` | No | – | Apify or custom proxy. **Residential proxy strongly recommended** |

> **Important**: TikTok aggressively blocks datacenter IPs.  Without a residential proxy the actor is likely to hit a CAPTCHA (Path 3).  Use Apify's `RESIDENTIAL` proxy group or any rotating residential proxy.

#### Local development

```bash
## Install CLI
npm install -g apify-cli

## Create local input
mkdir -p storage/key_value_stores/default
echo '{"hashtags":["roblox","minecraft"]}' > storage/key_value_stores/default/INPUT.json

## Run locally (no Docker, no proxy)
pip install apify playwright
playwright install chromium
apify run --purge
```

#### Deploy to Apify

```bash
apify login
apify push
```

***

### 中文

#### 功能说明

使用 Playwright 抓取 TikTok hashtag 级别的汇总数据，输出**精确到个位**的视频数（`video_count`）和累计播放量（`view_count`）。

Actor 用无头 Chromium 浏览器打开 `https://www.tiktok.com/tag/<hashtag>`，拦截 TikTok 页面自动发出的 `/api/challenge/detail` XHR 请求。该 XHR 返回的 `challengeInfo.statsV2` 包含精确整数（例如 `1 403 431 633 800`），远比页面上显示的缩写文字（"1.4T views"）精确。

#### 工作流程

```
浏览器打开 https://www.tiktok.com/tag/<hashtag>
        │
        ├─► 路径 1（主路）
        │   成功拦截 XHR /api/challenge/detail
        │   └─ statsV2.videoCount  ← 精确整数  ✓
        │   └─ statsV2.viewCount   ← 精确整数  ✓
        │
        ├─► 路径 2（DOM 兜底 — XHR 未被触发）
        │   读取页面可见文字：
        │   [data-e2e="challenge-vvcount"]    → view_count  (如 "1.4T views")
        │   [data-e2e="challenge-item-count"] → video_count (如 "100M videos")
        │   数值为 K/M/B/T 近似值
        │
        └─► 路径 3（失败）
            遭遇验证码或网络错误，error 字段非空
```

#### 输出字段说明

| 字段 | 类型 | 说明 |
|---|---|---|
| `hashtag` | string | TikTok 返回的 hashtag 规范名称 |
| `platform` | string | 固定为 `"tiktok"` |
| `challenge_id` | string | TikTok 内部 challenge ID |
| `video_count` | integer|null | 该 hashtag 下的视频总数 |
| `view_count` | integer|null | 累计总播放量 |
| `description` | string | hashtag 描述文字 |
| `is_commerce_hashtag` | bool | 是否为商业/品牌 hashtag |
| `share_meta_desc` | string | 分享简介文字 |
| `_source` | string | 数据来源路径标识 |
| `error` | string|null | 失败时非空，成功时为 null |

#### 示例输出（roblox）

```json
{
  "hashtag": "roblox",
  "challenge_id": "159721",
  "platform": "tiktok",
  "video_count": 100049186,
  "view_count": 1403431633800,
  "description": "Explore and find your own favourite way to play with #Roblox!",
  "is_commerce_hashtag": false,
  "share_meta_desc": "Watch awesome short videos created with trending hashtag #roblox",
  "_source": "Playwright /api/challenge/detail statsV2"
}
```

#### 输入参数

| 参数 | 必填 | 默认值 | 说明 |
|---|---|---|---|
| `hashtags` | 是 | – | hashtag 名称列表（不含 `#`），例如 `["roblox", "minecraft"]` |
| `proxyConfiguration` | 否 | – | 代理配置，**强烈建议使用住宅代理** |

> **注意**：TikTok 对数据中心 IP 的封锁非常激进。不使用住宅代理时极易触发验证码（路径 3）。建议选择 Apify `RESIDENTIAL` 代理组，或任意旋转住宅代理。

#### 本地调试

```bash
## 安装 Apify CLI
npm install -g apify-cli

## 创建本地输入文件
mkdir -p storage/key_value_stores/default
echo '{"hashtags":["roblox","minecraft"]}' > storage/key_value_stores/default/INPUT.json

## 本地运行（无 Docker，无代理）
pip install apify playwright
playwright install chromium
apify run --purge
```

#### 部署到 Apify

```bash
apify login
apify push
```

#### 成本参考

| 情况 | 用时 | 内存消耗 |
|---|---|---|
| 主路成功（无代理，本地） | ~12s/hashtag | ~400 MB |
| 主路成功（住宅代理） | ~15s/hashtag | ~400 MB |
| DOM 兜底 | ~30s/hashtag | ~400 MB |

Apify 平台按实际计算单元（CU）计费，单个 hashtag 预计消耗 **0.04–0.08 CU**。

# Actor input Schema

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

One or more hashtags to scrape (without #). E.g. \["roblox", "minecraft"]

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

Proxy settings. Residential proxy is strongly recommended — TikTok blocks datacenter IPs.

## Actor input object example

```json
{
  "hashtags": [
    "roblox"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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": [
        "roblox"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("funny_ground/tiktok-hashtag-stats").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": ["roblox"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("funny_ground/tiktok-hashtag-stats").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "roblox"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call funny_ground/tiktok-hashtag-stats --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=funny_ground/tiktok-hashtag-stats",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "TikTok Hashtag Stats",
        "description": "Scrapes TikTok hashtag summary data (exact video count & view count) using Playwright to intercept the /api/challenge/detail XHR. No login required.",
        "version": "0.1",
        "x-build-id": "EkZi0oS7IngxXLfW8"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/funny_ground~tiktok-hashtag-stats/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-funny_ground-tiktok-hashtag-stats",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/funny_ground~tiktok-hashtag-stats/runs": {
            "post": {
                "operationId": "runs-sync-funny_ground-tiktok-hashtag-stats",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/funny_ground~tiktok-hashtag-stats/run-sync": {
            "post": {
                "operationId": "run-sync-funny_ground-tiktok-hashtag-stats",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "hashtags"
                ],
                "properties": {
                    "hashtags": {
                        "title": "Hashtags",
                        "type": "array",
                        "description": "One or more hashtags to scrape (without #). E.g. [\"roblox\", \"minecraft\"]",
                        "items": {
                            "type": "string"
                        }
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings. Residential proxy is strongly recommended — TikTok blocks datacenter IPs."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
