# TikTok \[only $0.9💰]  Ad Library & Hashtag Trends Scraper (`memo23/tiktok-ads-scraper-cheerio`) Actor

💰$0.9 per 1,000 results. Unlock TikTok's viral potential with real-time hashtag analytics, audience insights, and trend data—transform raw metrics into winning strategies with precision-scraped engagement stats, demographic breakdowns, and competitive intelligence that keep you ahead in the game.

- **URL**: https://apify.com/memo23/tiktok-ads-scraper-cheerio.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 129 total users, 6 monthly users, 96.5% runs succeeded, 8 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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 Ads & Trends Scraper

**Three scrapers in one actor.** Pick a mode and run:

- 📊 **Trends mode** — the top trending hashtags from the TikTok Creative Center, each with rank, post count, total views, a popularity curve, and top creators. Leave the country empty to sweep 27 markets in one run.
- 🏆 **Top Ads mode** — the best-performing ad creatives from the TikTok Creative Center, ranked by CTR / likes / spend, with **CTR, cost, likes, comments, shares, campaign objective, target countries, landing page and video URLs** (37 fields per ad).
- 🔍 **Ad Library mode** — individual ad creatives from the official TikTok Ad Library (`library.tiktok.com`): advertiser, video + cover, images, first/last-shown dates, estimated audience size, and moderation/rejection info. Searchable by keyword or advertiser, across the EU/EEA + UK + TR.

***

### Overview

Three distinct TikTok data sources, one actor:

| Mode | Data source | Best for |
|---|---|---|
| **Trends** | `ads.tiktok.com/business/creativecenter` (hashtags) | Discovering what's *organically* popular — for content strategy, hashtag research, industry benchmarking |
| **Top Ads** | `ads.tiktok.com/creative_radar_api` (Top Ads board) | Studying the *best-performing paid creatives* — for hook research, swipe files, CTR benchmarking |
| **Ad Library** | `library.tiktok.com` (Ad Library + Other Commercial Content) | Auditing what *paid ads* a brand is running, and disclosed branded creator posts — for competitive analysis and ad-transparency research |

Choose your mode with the `mode` input field. The relevant filter group is the only one you need to fill in — fields outside the active mode are ignored.

> **⚠️ Ad Library availability:** TikTok's Ad Library is a DSA-compliance transparency tool, so it only covers ads shown in **EU/EEA + United Kingdom + Türkiye** (33 regions: AT, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK, TR). Other country values silently fall back to *all regions* with a warning in the log.

***

### Features

#### All modes

- **Mode switch**: pick *Trends*, *Top Ads*, or *Ad Library* with one input field
- **Country / region filter** shared across modes
- **`resultsLimit`** caps the dataset for cost control
- **Proxy support** with built-in Apify Proxy integration
- **Concurrency tuning** (`maxConcurrency` / `minConcurrency`)
- **Retry control** with graceful skip on TikTok-side errors

#### Trends mode

- **Time window** of 7 / 30 / 120 days
- **Multi-market sweep** — leave `country` empty to collect all 27 supported markets in one run
- **Rich rows** — rank, post count, total views, popularity time-series, top creators, direct Creative Center link

#### Top Ads mode

- **Ranking window** of 7 / 30 / 180 days
- **Rank by** For You / CTR / 2-second play rate / 6-second play rate / conversion rate (CVR) / likes / impressions / spend
- **Industry filter incl. sub-categories** — the full Creative Center taxonomy (21 top-level industries + 267 sub-categories, e.g. *Beauty & Personal Care > Skincare*), applied server-side
- **More filters** — target country, campaign objective, ad language, Spark vs Non-Spark ad format
- **Client-side refinement** — `keyword` (title/brand contains) and `minLikes`
- **Full engagement + performance** per ad — CTR (with computed benchmark tier), cost, likes, comments, shares, favorites
- **Full detail toggle** (`extractDetails`) — adds target country list, landing page, keyword list and objectives from each ad's detail page
- **Video URLs in up to five renditions** (360p–1080p) plus `videoUrlBest`, cover image, and the Creative Center link

#### Ad Library mode

- **Paste-a-URL shortcut** (`startUrl`) — copy a filtered URL straight from `library.tiktok.com` and the actor parses region, search terms, advertiser, sort, and date range out of it
- **Two library surfaces** (`sourceType`) — *Ad Library* (paid ads with transparency data) or *Other Commercial Content* (disclosed branded creator posts)
- **Search by keyword or advertiser name** (with `"…"` for exact-phrase match)
- **Date range** (`startDate` / `endDate` — defaults to the last 30 days)
- **Sort by** last-shown / first-shown date, or by reach / views (largest or smallest first)
- **API-first extraction** — reads a pre-warmed signing token, then pages the library APIs over plain HTTP (fast, no browser-per-ad)
- **Full pagination with dedupe** across all matching items up to `resultsLimit`

***

### How to Use

1. **Pick a mode**: choose *Trends*, *Top Ads*, or *Ad Library* via the `mode` field.
2. **Fill in the matching filter group** — the input form groups fields under each mode's section.
3. **Run** on Apify (or locally with `npm start`).
4. **Export** results as JSON, CSV, or Excel from the Apify dataset view.

***

### Input Configuration

#### Example — Trends mode

```json
{
    "mode": "trends",
    "country": "",
    "days": 7,
    "resultsLimit": 100,
    "proxy": { "useApifyProxy": true }
}
```

> Set `country` to a two-letter code (e.g. `"US"`) for a single market, or leave it empty to sweep all 27 supported markets. `days` is the trend window (7 / 30 / 120). Each hashtag row includes `rank`, `publishCount`, `views`, a `popularityCurve` time-series and `topCreators`.

#### Example — Top Ads mode

```json
{
    "mode": "topAds",
    "country": "US",
    "period": 30,
    "orderBy": "ctr",
    "industryId": "14103000000",
    "adFormat": "spark_ads",
    "extractDetails": true,
    "resultsLimit": 100,
    "proxy": { "useApifyProxy": true }
}
```

> `industryId` accepts the full Creative Center taxonomy — the example narrows the board to *Beauty & Personal Care > Skincare*. Leave it unset for all industries.

#### Example — Ad Library mode

```json
{
    "mode": "adLibrary",
    "country": "DE",
    "searchQuery": "nike",
    "advertiserName": "",
    "startDate": "2026-04-01",
    "endDate": "2026-05-07",
    "sortBy": "last_shown_date,desc",
    "resultsLimit": 60,
    "proxy": { "useApifyProxy": true }
}
```

#### Example — Ad Library via pasted URL

```json
{
    "mode": "adLibrary",
    "startUrl": "https://library.tiktok.com/ads?region=FR&adv_name=adidas&sort_type=last_shown_date,desc",
    "resultsLimit": 60,
    "proxy": { "useApifyProxy": true }
}
```

> Copy the URL straight out of your browser with filters applied — the actor parses region, search terms, advertiser, sort and date range from it (and auto-detects Ad Library vs Other Commercial Content). Discrete filter fields are ignored when `startUrl` is set.

#### Example — Other Commercial Content (branded creator posts)

```json
{
    "mode": "adLibrary",
    "sourceType": "other_commercial_content",
    "country": "DE",
    "sortBy": "views_high",
    "resultsLimit": 50,
    "proxy": { "useApifyProxy": true }
}
```

#### Input Parameters

##### 🎯 Start here — all modes

| Parameter | Type | Description | Default |
|---|---|---|---|
| **mode** | String | `"trends"` / `"topAds"` / `"adLibrary"` | `"trends"` |
| **country** | String | Two-letter country code, or `""` for all. Trends sweeps 27 markets when empty; Top Ads supports most major markets; Ad Library is restricted to EU/EEA + UK + TR (see Overview). | `"US"` |

##### 📊 Trends mode — only used when `mode = "trends"`

| Parameter | Type | Description | Default |
|---|---|---|---|
| **days** | String | Look-back window: `"7"` / `"30"` / `"120"` | `"7"` |

##### 🏆 Top Ads mode — only used when `mode = "topAds"`

| Parameter | Type | Description | Default |
|---|---|---|---|
| **period** | String | Ranking window: `"7"` / `"30"` / `"180"` days | `"30"` |
| **orderBy** | String | `for_you` / `ctr` / `play_2s_rate` / `play_6s_rate` / `cvr` / `like` / `impression` / `cost` | `for_you` |
| **industry** | String | Top-level industry (18 options) or `"all"` | `"all"` |
| **industryId** | String | Full-taxonomy industry pick incl. sub-categories (289 options, e.g. *Beauty & Personal Care > Skincare*). Overrides `industry` when set. | — |
| **objective** | String | Campaign objective (traffic, conversion, reach, app install, video views, lead gen, product sales, engagement) | all |
| **adLanguage** | String | Two-letter language code of the ad copy | all |
| **adFormat** | String | `spark_ads` / `non_spark_ads` (empty = all) | all |
| **keyword** | String | Client-side filter — keeps ads whose title or brand contains this text | — |
| **minLikes** | Integer | Client-side filter — keeps ads with at least this many likes | — |
| **extractDetails** | Boolean | Fetch each ad's detail endpoint for target countries, landing page, keyword list, objectives | `true` |

##### 🔍 Ad Library mode — only used when `mode = "adLibrary"`

| Parameter | Type | Description | Default |
|---|---|---|---|
| **startUrl** | String | Paste a filtered `library.tiktok.com` URL — filters are parsed from it and the fields below are ignored | — |
| **sourceType** | String | `ad_library` (paid ads) or `other_commercial_content` (branded creator posts) | `ad_library` |
| **searchQuery** | String | Keyword or advertiser name to search. Wrap in `"…"` for exact-phrase match. In Other Commercial Content mode this matches the creator's username. | `"nike"` |
| **advertiserName** | String | Optional filter by registered advertiser name (Ad Library only) | — |
| **startDate** | String | Earliest *last-shown* / *posted* date (YYYY-MM-DD) | 30 days ago |
| **endDate** | String | Latest *last-shown* / *posted* date (YYYY-MM-DD) | today |
| **sortBy** | String | `last_shown_date,desc` / `last_shown_date,asc` / `first_shown_date,desc` / `first_shown_date,asc` / `reach_high` / `reach_low` / `views_high` / `views_low` | `last_shown_date,desc` |

##### 📦 Output & limits — all modes

| Parameter | Type | Description | Default |
|---|---|---|---|
| **resultsLimit** | Integer | Hard cap on dataset rows | 100 |
| **maxConcurrency** | Integer | Maximum parallel requests | 10 |
| **minConcurrency** | Integer | Minimum parallel requests | 1 |
| **maxRequestRetries** | Integer | Retries per failed request before skipping | 8 |
| **proxy** | Object | Proxy configuration (Apify Proxy recommended) | Apify Proxy |

***

### Output Structure

The actor produces a **different row shape per mode**, distinguishable by the `type` field:

- **Trends rows** (`type: "hashtag_trend"`): `hashtagName`, `rank`, `country`, `period`, `publishCount`, `views`, `industryIds`, a `popularityCurve` time-series, and `topCreators`. See [Trends mode output](#trends-mode-output).
- **Top Ads rows** (`type: "top_ad"`): 37 fields per ad — rank, title, brand, CTR (+ computed tier), cost, likes/comments/shares, objective, industry, target countries, landing page, and video URLs in up to five renditions. See [Top Ads mode output](#top-ads-mode-output).
- **Ad Library rows** (`type: "ad"`): `adId`, `advertiserName`, `adTitle`, `videoUrl`, `videoCover`, `imageUrls`, `firstShownDate` / `lastShownDate`, `estimatedAudience`, `rejectionInfo`, `region`. See [Ad Library mode output](#ad-library-mode-output).
- **Other Commercial Content rows** (`type: "commercial_content"`): creator username, view buckets, posted date, video/cover URLs. See [Other Commercial Content output](#other-commercial-content-output).

If you need several row shapes in one place, run the actor once per mode and join on whatever business key you need (e.g. advertiser name).

***

### Trends mode output

The Trends-mode scraper provides detailed information for each hashtag. Here's the complete field documentation based on the JSON structure:

#### Sample row

```json
{
    "type": "hashtag_trend",
    "hashtagId": "7659867926865903649",
    "hashtagName": "marvelrivalss9",
    "rank": 1,
    "country": "US",
    "period": 7,
    "publishCount": 133653,
    "views": 37575559,
    "industryIds": ["25000000000"],
    "popularityCurve": [
        { "timestamp": 1783382400, "value": 0 },
        { "timestamp": 1783555200, "value": 24.68 },
        { "timestamp": 1783728000, "value": 100 }
    ],
    "topCreators": [
        { "creatorId": "0", "nickname": null, "avatarUrl": "https://p16-common-sign.tiktokcdn.com/..." }
    ],
    "link": "https://ads.tiktok.com/business/creativecenter/hashtag/marvelrivalss9/pc/en?countryCode=US&period=7",
    "scrapedAt": "2026-07-16T07:15:00.000Z"
}
```

#### Field descriptions — Trends mode

| Field | Type | Description |
|---|---|---|
| `type` | string | Always `"hashtag_trend"`. |
| `hashtagId` / `hashtagName` | string | TikTok's hashtag identifier and name (without the `#`). |
| `rank` | number | Rank within the country + period slice (1 = top). |
| `country` / `period` | string / number | The market and trend window (7 / 30 / 120 days) this row came from. |
| `publishCount` | number | Number of posts using the hashtag. |
| `views` | number | Total video views for the hashtag. |
| `industryIds` | string\[] | Creative Center industry IDs the hashtag maps to. |
| `popularityCurve` | array | Popularity time-series — `[{ timestamp (unix s), value (0–100 index) }]`. |
| `topCreators` | array | Notable creators using the hashtag — `[{ creatorId, nickname, avatarUrl }]`. |
| `link` | string | Direct Creative Center page for the hashtag. |
| `scrapedAt` | string | ISO timestamp of extraction. |

> **Note on volume:** the Creative Center's public (logged-out) hashtag surface exposes the **top 3 hashtags per country × period**. Leaving `country` empty sweeps all 27 supported markets in one run to build a larger dataset. (TikTok deprecated the older bulk hashtag endpoint in 2026.)

### Top Ads mode output

One row per ad from the Creative Center Top Ads board, in true ranking order.

#### Sample row (abridged)

```json
{
    "type": "top_ad",
    "adId": "7069234203623735297",
    "rank": 1,
    "adTitle": "Shop the viral serum everyone's talking about",
    "brandName": "medicube",
    "ctr": 1.84,
    "ctrTier": "high",
    "cost": 2,
    "likes": 40719,
    "comments": 212,
    "shares": 1183,
    "favorite": 3216,
    "objectiveKey": "campaign_objective_conversion",
    "industryKey": "label_14103000000",
    "industryName": "Skincare",
    "keywordList": ["serum", "skincare"],
    "countryCodes": ["US"],
    "landingPage": "https://…",
    "videoDuration": 27.5,
    "videoCover": "https://p16-….jpeg",
    "videoUrl720p": "https://v16m-….mp4",
    "videoUrl1080p": "https://v16m-….mp4",
    "videoUrlBest": "https://v16m-….mp4",
    "period": 30,
    "orderBy": "for_you",
    "countryCode": "US",
    "creativeCenterUrl": "https://ads.tiktok.com/business/creativecenter/topads/7069234203623735297/pc/en",
    "detailFetched": true,
    "scrapedAt": "2026-07-31T21:00:00.000Z"
}
```

#### Field notes — Top Ads mode

| Field | Description |
|---|---|
| `rank` | The ad's true position in TikTok's ranking, independent of client-side filters. |
| `ctr` / `ctrTier` | Click-through rate (%) and a benchmark band (`low` / `average` / `high` / `exceptional`) computed by the actor from fixed CTR thresholds. |
| `cost` | TikTok's relative spend score (1–5), not a currency amount. |
| `industryKey` / `industryName` | TikTok's opaque industry code and its human-readable label, resolved via the full 549-entry Creative Center taxonomy (sub-categories included). |
| `countryCodes`, `landingPage`, `keywordList`, `objectives` | Populated when `extractDetails` is on (one extra request per ad). |
| `videoUrl360p`–`videoUrl1080p`, `videoUrlBest` | All renditions TikTok returns; `videoUrlBest` is the highest available. CDN links are signed and typically expire within 24–48 h — download promptly if you archive. |

> **Note on volume:** the anonymous Top Ads surface serves **only the first page (~20 ads) per (ranking × industry × country × period) combination** — deeper pages require TikTok login. To build bigger datasets, sweep multiple industries (289 taxonomy options), rankings (8 `orderBy` values), and periods.

### Ad Library mode output

Each row is one ad from the official TikTok Ad Library, retrieved over the public API (the actor warms one signing token via a single headless page-load, then pages the search endpoint over plain HTTP).

#### Sample row

```json
{
    "type": "ad",
    "adId": "1870848124471298",
    "advertiserName": "S.F. TRADING S.R.L.",
    "adTitle": "Relax Your Body with a Professional Massage",
    "adType": "2",
    "auditStatus": "1",
    "sorAuditStatus": "1",
    "firstShownDate": 1784179992000,
    "lastShownDate": 1784179992000,
    "estimatedAudience": "0-1K",
    "impressions": 0,
    "spent": "",
    "showMode": 1,
    "videoUrl": "https://library.tiktok.com/api/v1/cdn/.../video/...",
    "videoCover": "https://p16-common-sign.tiktokcdn.com/...",
    "imageUrls": [],
    "rejectionInfo": null,
    "region": "DE",
    "matchedQuery": "nike",
    "matchedAdvertiser": null,
    "adDetailUrl": "https://library.tiktok.com/ads/detail?ad_id=1870848124471298&region=DE",
    "scrapedAt": "2026-07-16T07:57:00.000Z"
}
```

#### Field descriptions — Ad Library mode

| Field | Type | Description |
|---|---|---|
| `type` | string | Always `"ad"`. |
| `adId` | string | TikTok's ad identifier. |
| `advertiserName` | string | The advertiser / page name. |
| `adTitle` | string | The ad's creative title / caption (when present). |
| `adType` | string | TikTok's internal ad-type code. |
| `auditStatus` / `sorAuditStatus` | string | Moderation status codes. |
| `firstShownDate` / `lastShownDate` | number | Unix ms timestamps for the ad's active window. |
| `estimatedAudience` | string | Audience-size bucket (e.g. `"0-1K"`). |
| `impressions` | number | Reported impressions (often 0 for small ads). |
| `spent` | string | Reported spend bucket, when disclosed. |
| `videoUrl` / `videoCover` | string | Ad video and cover image URLs. |
| `imageUrls` | string\[] | Static image creatives, when present. |
| `rejectionInfo` | object | null | Policy-rejection detail — `reasons`, `affected_regions`, when the ad was actioned. |
| `region` | string | The Ad Library region the ad was matched in. |
| `matchedQuery` / `matchedAdvertiser` | string | The keyword / advertiser filter that surfaced this ad. |
| `adDetailUrl` | string | Link to the ad's Ad Library detail page. |
| `scrapedAt` | string | ISO timestamp of extraction. |

> **Coverage:** the TikTok Ad Library only covers **EU/EEA + UK + Turkey**. Set `country` to a supported code (e.g. `DE`, `FR`, `GB`) — other values fall back to `all`. Per-ad audience *targeting* (age/gender/interest breakdown) lives behind a separate per-ad-signed endpoint and is not included in this bulk export.

### Other Commercial Content output

When `sourceType` is `other_commercial_content` (or the pasted `startUrl` points at that surface), each row is one disclosed branded creator post.

#### Sample row

```json
{
    "type": "commercial_content",
    "contentId": "v26044gc0000d92o8tvog65laio69740",
    "creatorUsername": "nikolaisavic",
    "creatorProfileUrl": "https://www.tiktok.com/@nikolaisavic",
    "brandNames": [],
    "contentLabel": "1",
    "auditStatus": "1",
    "showMode": "1",
    "postedTime": "1782941168",
    "postedAt": "2026-07-01T21:26:08.000Z",
    "videoViews": "20M-30M",
    "contentViews": "20M-30M",
    "videoUrl": "https://library.tiktok.com/api/v1/cdn/…/video/…",
    "videoCover": "https://p16-common-sign.tiktokcdn.com/…",
    "imageUrls": [],
    "region": "DE",
    "matchedQuery": null,
    "scrapedAt": "2026-07-31T21:06:49.101Z"
}
```

#### Field notes — Other Commercial Content

| Field | Description |
|---|---|
| `contentId` | TikTok video id — **empty for photo posts** (`showMode: "2"`). |
| `creatorUsername` / `creatorProfileUrl` | The posting creator. TikTok's transparency surface exposes only the username (no display name / follower count at this level). |
| `brandNames` | Disclosed partner brands. TikTok returns this field but it is empty on the vast majority of posts. |
| `showMode` | `"1"` = video post, `"2"` = photo post. |
| `videoViews` / `contentViews` | View-count buckets (e.g. `"0-1K"`, `"20M-30M"`) — TikTok does not expose exact counts. |
| `postedTime` / `postedAt` | Post date as unix seconds and ISO timestamp. |

> **Search behaviour:** on this surface, `searchQuery` matches the **creator's username** (brand-keyword search is not supported by TikTok's API and returns 0 results). Sorting supports posted date and video views (`views_high` / `views_low`); reach options map to the views sort.

### Key Notes

1. **Data Freshness**: All three sources update frequently — Trends near real-time, Top Ads as the board refreshes, Ad Library when ads are submitted/audited.
2. **Rate Limits**: The actor handles TikTok's rate limiting gracefully — failed requests are retried with backoff, and TikTok-side error codes are treated as skip-not-retry where retrying can't help, to avoid retry storms.
3. **Proxies Recommended**: Using residential proxies helps avoid IP-based rate limiting on the Creative Center endpoints.
4. **Ad Library coverage**: The Ad Library (both surfaces) is only available for EU/EEA + UK + TR. Country values outside that list fall back to *all*.
5. **Top Ads depth**: The anonymous Creative Center serves only the first ~20 ads per filter combination — sweep industries/rankings/periods for volume (deeper pages and keyword search are login-gated by TikTok).
6. **Data Availability**: Some metrics are bucketed by TikTok (audience and view ranges like `"10M-20M"`), spend is a relative 1–5 score in Top Ads, and signed CDN video links typically expire within 24–48 hours.

***

### Explore More Scrapers

If you found this TikTok Ads Scraper useful, check out the rest of the TikTok toolkit:

- **[TikTok Followers & Following Scraper](https://apify.com/memo23/tiktok-followers-scraper)** — followers, following, and suggested accounts with per-account stats
- **[TikTok Hashtag Scraper](https://apify.com/memo23/tiktok-hashtag-scraper)** — every video posted under a hashtag, with engagement stats and creator follower counts
- **[TikTok Search Scraper](https://apify.com/memo23/tiktok-search-scraper)** — TikTok's ranked search results for any keyword
- **[Social Video Transcript Scraper](https://apify.com/memo23/tiktok-profile-videos-cheerio)** — captions and AI transcripts for TikTok and Instagram videos

Browse the full portfolio at [memo23's Apify profile](https://apify.com/memo23).

### Support

- For issues or feature requests, please use the [Issues](https://console.apify.com/actors/gdVQ69aZFVH0R2Itg/issues) section of this actor.
- If you need customization or have questions, feel free to contact the author:
  - Author's website: <https://muhamed-didovic.github.io/>
  - Email: <muhamed.didovic@gmail.com>

### Additional Services

- Request customization or whole dataset: <muhamed.didovic@gmail.com>
- If you need anything else scraped, or this actor customized, email: <muhamed.didovic@gmail.com>
- For API services of this scraper (no Apify fee, just usage fee for the API), contact: <muhamed.didovic@gmail.com>
- Email: muhamed.didovic@gmail.com

# Actor input Schema

## `mode` (type: `string`):

<b>Trends</b> = popular hashtags from the TikTok Creative Center (rank, post counts, weekly trend).<br><b>Top Ads</b> = the best-performing ad creatives from the Creative Center, ranked by CTR / likes / cost, with video URLs, landing page, objective and engagement.<br><b>Ad Library</b> = individual ad creatives from library.tiktok.com (advertiser, video, targeting by age/gender/region, etc.).

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

Two-letter country code. Empty string means <i>all regions</i> (Ad Library mode) or <i>unset</i> (Trends mode).<br><b>Ad Library mode is only available in EU/EEA + UK + TR</b> (AT, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK, TR). Other values silently fall back to <i>all</i>.

## `days` (type: `string`):

Look-back period for trending hashtags.

## `industry` (type: `string`):

Restrict trending hashtags to a single industry, or pick <i>All</i> to scrape every industry.

## `isNewToTop100` (type: `boolean`):

If checked, only return hashtags that newly entered the Top 100 in the chosen window.

## `startUrl` (type: `string`):

Paste a URL from <code>library.tiktok.com/ads</code> or <code>library.tiktok.com/other-commercial-content</code> (with your filters applied). The actor extracts <code>region</code>, <code>search\_terms</code>, <code>adv\_name</code>, <code>sort\_type</code>, <code>start\_time</code>, <code>end\_time</code>, strips pagination params, and auto-detects the mode (ad library vs commercial content). Leave empty to use the discrete filter fields below.

## `sourceType` (type: `string`):

Which library surface to scrape when no URL is supplied. <b>Ad Library</b> = paid TikTok ads with advertiser transparency data. <b>Other Commercial Content</b> = branded creator posts (disclosed brand partnerships).

## `searchQuery` (type: `string`):

Keyword or advertiser name to search. Wrap in <code>"…"</code> for exact-phrase match. In Other Commercial Content mode, this searches creator username or brand name.

## `advertiserName` (type: `string`):

Optional filter by registered advertiser name. Ignored in Other Commercial Content mode.

## `startDate` (type: `string`):

Earliest <i>last-shown</i> / <i>posted</i> date to include (YYYY-MM-DD). Defaults to 30 days ago.

## `endDate` (type: `string`):

Latest <i>last-shown</i> / <i>posted</i> date to include (YYYY-MM-DD). Defaults to today.

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

Sort order for results. Reach / views options rank by TikTok's impression sort (Ad Library) or video-views sort (Other Commercial Content) — largest to smallest (high) or smallest to largest (low).

## `period` (type: `string`):

Lookback window for the top-ads ranking: last 7, 30, or 180 days.

## `orderBy` (type: `string`):

How the top ads are ranked.

## `industryId` (type: `string`):

Full Creative Center industry taxonomy — 21 top-level industries and their sub-categories (e.g. Beauty & Personal Care > Skincare). When set, this overrides the top-level Industry filter above for Top Ads mode. Leave unset to use the Industry filter.

## `objective` (type: `string`):

Filter ads by their campaign objective. Leave empty for all.

## `adLanguage` (type: `string`):

Two-letter language code to filter creatives by language (e.g. en, es, de). Leave empty for all.

## `adFormat` (type: `string`):

Restrict to Spark Ads (ads promoted from an existing organic TikTok post) or Non-Spark Ads (standalone ad creatives). Leave empty for all.

## `keyword` (type: `string`):

Top Ads only. Keeps just the ads whose title or brand name contains this text. Applied by the actor to the fetched ranking — TikTok's public Creative Center API has no server-side keyword search, so this filters results rather than querying TikTok. Example: nike. Leave empty for no filter.

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

Top Ads only. Keeps just the ads with at least this many likes. Applied by the actor to the fetched ranking (TikTok's public API exposes no like-tier filter). Example: 1000. Leave empty for no filter.

## `extractDetails` (type: `boolean`):

When on, fetches each ad's detail endpoint for the complete field set (target country list, landing page, comments/shares, keyword list, objectives). Off = faster/cheaper, list-level fields only (CTR, cost, likes, video).

## `resultsLimit` (type: `integer`):

Hard cap on the number of records pushed to the dataset. Applies to every mode — Trends stops after this many hashtags, Top Ads / Ad Library after this many ads.

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

Maximum number of parallel requests.

## `minConcurrency` (type: `integer`):

Minimum number of parallel requests.

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up.

## `proxy` (type: `object`):

Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you. Only set this if you want to use your own proxies.

## Actor input object example

```json
{
  "mode": "trends",
  "country": "US",
  "days": "7",
  "industry": "all",
  "isNewToTop100": false,
  "startUrl": "https://library.tiktok.com/ads?region=FR&adv_name=adidas&search_terms=%5B%22nike%22%5D&sort_type=last_shown_date%2Cdesc",
  "sourceType": "ad_library",
  "searchQuery": "pikoya",
  "sortBy": "last_shown_date,desc",
  "period": "30",
  "orderBy": "for_you",
  "industryId": "",
  "objective": "",
  "adLanguage": "",
  "adFormat": "",
  "keyword": "",
  "extractDetails": true,
  "resultsLimit": 100,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 8
}
```

# 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 = {
    "mode": "trends",
    "country": "US",
    "days": "7",
    "industry": "all",
    "sourceType": "ad_library",
    "searchQuery": "nike",
    "sortBy": "last_shown_date,desc"
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/tiktok-ads-scraper-cheerio").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 = {
    "mode": "trends",
    "country": "US",
    "days": "7",
    "industry": "all",
    "sourceType": "ad_library",
    "searchQuery": "nike",
    "sortBy": "last_shown_date,desc",
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/tiktok-ads-scraper-cheerio").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 '{
  "mode": "trends",
  "country": "US",
  "days": "7",
  "industry": "all",
  "sourceType": "ad_library",
  "searchQuery": "nike",
  "sortBy": "last_shown_date,desc"
}' |
apify call memo23/tiktok-ads-scraper-cheerio --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/gdVQ69aZFVH0R2Itg/builds/xQSRHNftkOwKrRBPJ/openapi.json
