# TikTok Hashtag Scraper — Videos, Creators & Follower Counts (`unfenced-group/tiktok-hashtag-scraper`) Actor

Scrape TikTok videos by hashtag and get the creator behind each video: exact follower count, total likes, verified status, bio link, business category and join date, plus plays, likes, comments, shares and saves per video. One row per video or per unique creator. No login needed.

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

## Pricing

from $0.43 / 1,000 results

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

![TikTok Hashtag Scraper](https://api.apify.com/v2/key-value-stores/EhGIXuJuqMo3PwUG8/records/banner.png)

Scrape TikTok videos by hashtag and get the creator behind every video: exact follower count, total likes, verified status, bio link, business category and join date, together with each video's plays, likes, comments, shares and saves. Get one row per video, or one row per unique creator for influencer discovery. No login, cookies or API key required.

***

### Why this scraper?

#### 👤 Know who posted it

Every video comes with its creator: username, display name, profile URL, verified status, private-account flag and bio.

#### 🔢 Exact follower counts

TikTok's hashtag feed rounds audience numbers (5.8M). This scraper reads each creator's profile and returns the exact figure (5,760,883), plus following, total likes, video count and friends.

#### 🏷️ Creator profile details

Bio link, business category, business, organisation and TikTok Shop seller flags, account language and the date the account was created.

#### 📈 Full video metrics

Plays, likes, comments, shares and saves per video, an engagement rate, caption, all hashtags and mentions, music, duration, resolution, location tag and posting date.

#### 🧑‍🤝‍🧑 Creator mode for influencer research

Switch to one row per creator to see who posts under a hashtag, how many of their videos appeared, their total and average plays, and engagement relative to their follower count.

#### 🎯 Filters and monitoring

Minimum follower count, a posting-date window, several hashtags per run with duplicates removed, and an option to skip anything a previous run already returned.

***

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `hashtags` | array | (required) | Hashtags to scrape, with or without `#`. Full tag URLs such as `https://www.tiktok.com/tag/skincare` also work. |
| `maxVideosPerHashtag` | integer | `100` | Maximum videos to collect per hashtag (1 to 1,000). TikTok shows roughly 150 to 250 per hashtag to a logged-out visitor. |
| `resultType` | string | `"videos"` | `videos` for one row per video, `creators` for one row per unique creator. |
| `fetchCreatorProfiles` | boolean | `true` | Read each creator's profile for exact counts, bio link, category, account flags and join date. Turn off for faster runs with TikTok's rounded counts. |
| `minFollowers` | integer | `0` | Only return videos or creators whose creator has at least this many followers. `0` means no limit. |
| `publishedWithinDays` | integer | (empty) | Only return videos posted in the last N days. Empty means any date. |
| `skipAlreadySeen` | boolean | `false` | Skip videos (or creators in creator mode) returned by an earlier run in the last 90 days. |

***

### Output schema

Fields the source does not publish for a given video or creator are returned as `null` rather than omitted.

#### Result type `videos` (one row per video)

| Field | Type | Description |
|---|---|---|
| `id` | string | TikTok video ID |
| `url` | string | Link to the video |
| `searchHashtag` | string | The hashtag from your input that returned this video |
| `description` | string | Video caption |
| `language` | string | Caption language code detected by TikTok, e.g. `en` |
| `hashtags` | array | All hashtags in the caption |
| `mentions` | array | Usernames mentioned in the caption |
| `publishDate` | string | Posting date, `YYYY-MM-DD` (UTC) |
| `publishDateISO` | string | Posting date and time, ISO 8601 |
| `playCount` | integer | Views (TikTok rounds large numbers) |
| `likeCount` | integer | Likes |
| `commentCount` | integer | Comments |
| `shareCount` | integer | Shares |
| `saveCount` | integer | Times saved to favourites |
| `engagementRate` | number | (likes + comments + shares + saves) ÷ plays |
| `durationSeconds` | integer | Video length in seconds |
| `videoWidth` | integer | Width in pixels |
| `videoHeight` | integer | Height in pixels |
| `videoQuality` | string | Resolution label, e.g. `720p` |
| `isAd` | boolean | TikTok marks the post as an ad or as authorised for use in ads |
| `musicId` | string | Sound ID |
| `musicTitle` | string | Sound title |
| `musicAuthor` | string | Sound artist or uploader |
| `musicIsOriginal` | boolean | Whether the sound is the creator's original audio |
| `locationName` | string | Tagged place (null when no place is tagged, which is most videos) |
| `locationAddress` | string | Address of the tagged place |
| `locationCity` | string | City of the tagged place |
| `locationCategory` | string | Type of the tagged place, e.g. `Outdoors and Attractions` |
| `creatorId` | string | Creator's TikTok user ID |
| `creatorUsername` | string | Creator's handle, without `@` |
| `creatorNickname` | string | Creator's display name |
| `creatorProfileUrl` | string | Link to the creator's profile |
| `creatorSecUid` | string | Creator's secure user ID, used by other TikTok tools |
| `creatorVerified` | boolean | Verified badge |
| `creatorPrivateAccount` | boolean | Private account |
| `creatorBio` | string | Profile bio. Email addresses and phone numbers are removed |
| `creatorBioLink` | string | Website link on the profile (requires `fetchCreatorProfiles`) |
| `creatorCategory` | string | Business category, e.g. `Shopping & Retail` (business accounts only; requires `fetchCreatorProfiles`) |
| `creatorIsBusinessAccount` | boolean | Business account (requires `fetchCreatorProfiles`) |
| `creatorIsOrganization` | boolean | Organisation account (requires `fetchCreatorProfiles`) |
| `creatorIsShopSeller` | boolean | TikTok Shop seller (requires `fetchCreatorProfiles`) |
| `creatorLanguage` | string | Account language (requires `fetchCreatorProfiles`) |
| `creatorJoinedDate` | string | Account creation date, ISO 8601 (requires `fetchCreatorProfiles`) |
| `creatorFollowers` | integer | Followers. Exact when `creatorStatsExact` is true, TikTok's rounded figure otherwise |
| `creatorFollowing` | integer | Accounts the creator follows |
| `creatorTotalLikes` | integer | Total likes across all the creator's videos |
| `creatorVideoCount` | integer | Number of videos on the profile |
| `creatorFriends` | integer | Mutual follows |
| `creatorStatsExact` | boolean | `true` when the counts come from the profile page and are exact |
| `creatorProfileStatus` | string | `OK`, `PRIVATE`, `UNAVAILABLE`, `FAILED` or `NOT_REQUESTED` |
| `hashtagId` | string | TikTok ID of the searched hashtag |
| `hashtagViewCount` | integer | Total views of all videos under the searched hashtag |
| `hashtagVideoCount` | integer | Total number of videos under the searched hashtag |
| `source` | string | Always `tiktok.com` |
| `scrapedAt` | string | When the row was collected, ISO 8601 |
| `contentHash` | string | Short fingerprint of the video ID and caption, for change detection |

#### Result type `creators` (one row per unique creator)

| Field | Type | Description |
|---|---|---|
| `id` | string | Creator's TikTok user ID |
| `username` | string | Handle, without `@` |
| `nickname` | string | Display name |
| `profileUrl` | string | Link to the profile |
| `secUid` | string | Secure user ID |
| `verified` | boolean | Verified badge |
| `privateAccount` | boolean | Private account |
| `bio` | string | Profile bio, email addresses and phone numbers removed |
| `bioLink` | string | Website link on the profile |
| `category` | string | Business category (business accounts only) |
| `isBusinessAccount` | boolean | Business account |
| `isOrganization` | boolean | Organisation account |
| `isShopSeller` | boolean | TikTok Shop seller |
| `language` | string | Account language |
| `joinedDate` | string | Account creation date, ISO 8601 |
| `followers` | integer | Followers |
| `following` | integer | Accounts followed |
| `totalLikes` | integer | Total likes received |
| `videoCount` | integer | Videos on the profile |
| `friends` | integer | Mutual follows |
| `statsExact` | boolean | `true` when counts are exact |
| `profileStatus` | string | `OK`, `PRIVATE`, `UNAVAILABLE`, `FAILED` or `NOT_REQUESTED` |
| `matchedHashtags` | array | Which of your hashtags this creator appeared under |
| `videosFound` | integer | How many of the creator's videos appeared under those hashtags |
| `hashtagPlays` | integer | Total plays of those videos |
| `hashtagLikes` | integer | Total likes of those videos |
| `hashtagComments` | integer | Total comments of those videos |
| `hashtagShares` | integer | Total shares of those videos |
| `avgPlaysPerVideo` | integer | Average plays per video found |
| `avgEngagementRate` | number | (likes + comments + shares + saves) ÷ plays across those videos |
| `followerEngagementRate` | number | Average likes, comments and shares per video ÷ followers |
| `topVideoUrl` | string | The creator's most-played video under your hashtags |
| `topVideoPlays` | integer | Plays of that video |
| `latestVideoDate` | string | Newest of those videos, ISO 8601 |
| `videoUrls` | array | Up to 10 of the creator's video links found |
| `source` | string | Always `tiktok.com` |
| `scrapedAt` | string | When the row was collected |
| `contentHash` | string | Short fingerprint of the creator ID and handle |

#### Example record (`videos`)

```json
{
    "id": "7691137555370167582",
    "url": "https://www.tiktok.com/@glowwithmaya/video/7691137555370167582",
    "searchHashtag": "skincare",
    "description": "My 3-step night routine for dry skin #skincare #nightroutine #glassskin",
    "language": "en",
    "hashtags": ["skincare", "nightroutine", "glassskin"],
    "mentions": ["cerave"],
    "publishDate": "2026-09-30",
    "publishDateISO": "2026-09-30T01:41:55.000Z",
    "playCount": 2400000,
    "likeCount": 186000,
    "commentCount": 1942,
    "shareCount": 8310,
    "saveCount": 21400,
    "engagementRate": 0.0905,
    "durationSeconds": 41,
    "videoWidth": 720,
    "videoHeight": 1280,
    "videoQuality": "720p",
    "isAd": false,
    "musicId": "7600943865013143553",
    "musicTitle": "original sound - glowwithmaya",
    "musicAuthor": "Maya",
    "musicIsOriginal": true,
    "locationName": "Napa Valley",
    "locationAddress": "1040 Orchard Ave, Napa, CA 94558, United States",
    "locationCity": "Napa",
    "locationCategory": "Outdoors and Attractions",
    "creatorId": "6898972998808650758",
    "creatorUsername": "glowwithmaya",
    "creatorNickname": "Maya | Skincare",
    "creatorProfileUrl": "https://www.tiktok.com/@glowwithmaya",
    "creatorSecUid": "MS4wLjABAAAAes8LTqEPl7pyaRjPQxWH3ME-O8AQRamPbhIyqZDs2iSZyWF4yEEeg0ZiW5ZQBaQQ",
    "creatorVerified": true,
    "creatorPrivateAccount": false,
    "creatorBio": "dry skin diaries\n[email removed]",
    "creatorBioLink": "https://linktr.ee/glowwithmaya",
    "creatorCategory": "Health & Beauty",
    "creatorIsBusinessAccount": true,
    "creatorIsOrganization": false,
    "creatorIsShopSeller": false,
    "creatorLanguage": "en",
    "creatorJoinedDate": "2020-03-06T01:51:44.000Z",
    "creatorFollowers": 1284906,
    "creatorFollowing": 446,
    "creatorTotalLikes": 37243740,
    "creatorVideoCount": 879,
    "creatorFriends": 97,
    "creatorStatsExact": true,
    "creatorProfileStatus": "OK",
    "hashtagId": "504245",
    "hashtagViewCount": 992180561161,
    "hashtagVideoCount": 61540286,
    "source": "tiktok.com",
    "scrapedAt": "2026-10-12T14:11:31.070Z",
    "contentHash": "d39931d96a527296"
}
```

***

### Examples

**Videos and creators under one hashtag:**

```json
{
    "hashtags": ["skincare"],
    "maxVideosPerHashtag": 150
}
```

**Find creators with at least 50,000 followers across several hashtags:**

```json
{
    "hashtags": ["booktok", "bookrecommendations", "romancebooks"],
    "maxVideosPerHashtag": 250,
    "resultType": "creators",
    "minFollowers": 50000
}
```

**Only videos from the last 30 days, without profile reads for speed:**

```json
{
    "hashtags": ["amsterdam", "#AmsterdamFood"],
    "publishedWithinDays": 30,
    "fetchCreatorProfiles": false
}
```

**Daily monitoring of a branded hashtag (schedule this run every day):**

```json
{
    "hashtags": ["yourbrandname"],
    "maxVideosPerHashtag": 250,
    "skipAlreadySeen": true
}
```

***

### 💰 Pricing

**$0.45 per 1,000 results**, plus a $0.001 start fee per run at the default memory. Results are only charged when saved to your dataset; videos removed by your filters and failed attempts are never charged.

| Results | Cost |
|---|---|
| 100 | ~$0.05 |
| 1,000 | ~$0.45 |
| 10,000 | ~$4.50 |
| 100,000 | ~$45.00 |

> Flat-rate alternatives typically charge $29–$49/month regardless of usage.

Subscription tiers lower the rate to $0.44 per 1,000 (Silver) and $0.43 per 1,000 (Gold and above). Use **Max videos per hashtag** to control your spend exactly.

***

### Performance

| Run | Typical time |
|---|---|
| 1 hashtag, 50 videos, with profiles | under 30 seconds |
| 1 hashtag, 150 videos, with profiles | about 2 minutes |
| 2 hashtags, 120 videos each, without profiles | about 1.5 minutes |
| 2 hashtags, all available videos, creator mode | 6–8 minutes |

***

### Known limitations

- TikTok shows a logged-out visitor roughly 150 to 250 videos per hashtag. The scraper opens extra sessions to reach the top of that range, but it cannot return a hashtag's full history.
- The hashtag feed is ranked by popularity, not date. A short `publishedWithinDays` window on an older hashtag can return few or no videos.
- Very broad hashtags such as `#fyp` return only a handful of videos; TikTok limits those feeds.
- Play counts are rounded by TikTok (e.g. 1,500,000). Follower counts are exact only when `fetchCreatorProfiles` is on.
- Profile pictures, video files and cover images are not included. Email addresses and phone numbers are removed from bios.
- Photo slideshows do not appear in TikTok's hashtag feed, so only videos are returned.

***

### Technical details

- **Source:** tiktok.com — public hashtag pages and public creator profiles
- **Coverage:** any public hashtag in any language, including non-Latin scripts
- **Deduplication:** a video found under two of your hashtags is returned once; `skipAlreadySeen` remembers results for 90 days
- **Retry:** automatic retry with a fresh browser when TikTok refuses a request

***

### Rate this actor

If this scraper does its job, a short review on the **Reviews** tab helps other users find it. Something not working? Open an issue on the **Issues** tab instead — issues get fixed.

***

### Need a custom scraper?

**[Unfenced Group](https://www.unfencedgroup.nl)** builds Apify actors for any website — for free.

If the site you need isn't in our portfolio yet, just ask. We scope, build, and publish it at no cost to you. You only pay for results — we absorb the compute and proxy costs ourselves. Same pay-per-result pricing, same quality, same standards as every actor in this portfolio.

**Get in touch:** [www.unfencedgroup.nl](https://www.unfencedgroup.nl)

# Actor input Schema

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

TikTok hashtags to scrape, with or without the # sign. A full tag URL such as https://www.tiktok.com/tag/skincare also works. Example: \["skincare", "booktok"].

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

Maximum number of videos to collect per hashtag. TikTok shows a logged-out visitor roughly 150 to 250 videos per hashtag, so values above that return what TikTok makes available. Example: 100.

## `resultType` (type: `string`):

"videos" returns one row per video with its creator's details. "creators" returns one row per unique creator found under the hashtags, with how many of their videos appeared and how those videos performed. Example: "creators".

## `fetchCreatorProfiles` (type: `boolean`):

Read each creator's profile for exact follower, following, like and video counts, plus bio link, business category, account type and join date. When off, counts are TikTok's rounded figures (for example 5,800,000 instead of 5,760,883) and profile-only fields are empty. Example: true.

## `minFollowers` (type: `integer`):

Only return videos (or creators) whose creator has at least this many followers. Use 0 for no limit. Example: 10000.

## `publishedWithinDays` (type: `integer`):

Only return videos posted in the last N days. Leave empty for any date. TikTok ranks hashtag videos by popularity, not by date, so a short window can return few videos. Example: 30.

## `skipAlreadySeen` (type: `boolean`):

Skip videos (or creators, in creator mode) that an earlier run of this actor already returned in the last 90 days. Useful for scheduled monitoring. Example: false.

## Actor input object example

```json
{
  "hashtags": [
    "skincare",
    "booktok"
  ],
  "maxVideosPerHashtag": 100,
  "resultType": "videos",
  "fetchCreatorProfiles": true,
  "minFollowers": 10000,
  "publishedWithinDays": 30,
  "skipAlreadySeen": false
}
```

# Actor output Schema

## `results` (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": [
        "skincare"
    ],
    "maxVideosPerHashtag": 50
};

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

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

```

## MCP server setup

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