# TikTok Ads Library & Top Ads Scraper — Targeting, Advertisers (`foxlabs/tiktok-ads-scraper`) Actor

TikTok ads from the Ad Library (EU, EEA, UK, Switzerland, Turkey): targeting, reach by country, age and gender, who paid, landing page. One-row-per-advertiser summaries, new-ads monitoring, and Creative Center Top Ads with likes, CTR rank and retention curves. No login.

- **URL**: https://apify.com/foxlabs/tiktok-ads-scraper.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (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.50 / 1,000 ad library ads

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/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 Ads Library & Top Ads Scraper — Targeting, Advertisers

Get **TikTok ads from the official Ad Library** (every ad shown in the EU, EEA, Switzerland, the UK and Turkey) with **targeting, unique users by country, age and gender, who paid for the ad, the advertiser's registered country and TikTok account, landing page and call to action** — or **TikTok Creative Center Top Ads** (best-performing ads in 28 countries) with likes, comments, shares, CTR rank, the video and second-by-second retention and CTR curves.

- 🔎 **Any advertiser or keyword** in the Ad Library, active and inactive ads, up to 5,000 ads per search term
- 🏢 **One row per advertiser**: ads found, first/last shown, countries, summed reach, landing domains, payer — or list the biggest TikTok advertisers in a country without a keyword
- 🎬 **Top Ads**: more than TikTok's 20-per-filter limit, without a login, by combining sort orders, objectives and industries
- 🔔 **Monitoring**: on a schedule, get only ads you have not received before

No TikTok account, no login, no cookies, no API key.

### Quick start (API)

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~tiktok-ads-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "library", "searchTerms": ["NIKE Retail B.V."], "searchBy": "advertiser", "datePreset": "last90", "maxAdsPerQuery": 20}'
```

### What you get

Three kinds of rows, each with every key present (`null` when TikTok publishes nothing). `recordType` tells them apart: `ad`, `advertiser`, `topAd`, and `status` for a search that returned nothing (free, with the reason in `error`).

#### Ad Library ads (`recordType: "ad"`)

| Group | Fields |
|---|---|
| Ad | `adId`, `adText`, `adFormat` (video, image, or null when TikTok shows no creative), `videoUrl`, `videoCoverUrl`, `imageUrls`, `mediaExpiresAt` (TikTok's signed media links expire — download before then), `landingUrl`, `landingDomain`, `appStoreUrl` (App Store / Google Play link of app promotion ads, which have no landing page), `callToAction`, `objective`, `category`, `removedReason` (TikTok's reason, for removed ads), `removedInCountries`, `adLibraryUrl` |
| When & how many | `firstShown`, `lastShown`, `daysShown`, `uniqueUsersSeen` (TikTok's range, e.g. `1M-10M`), `uniqueUsersSeenMin`, `uniqueUsersSeenMax` |
| Reach by country | `reachByCountry[]`: `country`, `uniqueUsers`, `uniqueUsersMin`, `uniqueUsersMax`, `byAgeAndGender[]` (`age`, `gender`, `uniqueUsers`) |
| Targeting | `targetCountries`, `targetAgeGroups[]` (per country), `targetGenders[]` (per country), `targetAudienceSize` (+ `Min`/`Max`), `targetInterests`, `targetOperatingSystems`, `customAudience`, `audienceExclusion`, `highSpendingPower`, `targetOther` (languages, devices, cities, video/creator interactions — only when TikTok lists any) |
| Advertiser | `advertiserName`, `advertiserBusinessId`, `paidBy` (the "Ad paid for by" entity, often the media agency), `advertiserCountry` (registered location), `advertiserTikTokUsername`, `advertiserTikTokFollowers` (+ `Text`), `advertiserTikTokUrl` |
| Search | `query`, `queryType`, `searchedRegions`, `dateFrom`, `dateTo`, `detailStatus` (`ok`, `not-requested`, `empty`, `failed`), `scrapedAt`, `error` |

Everything in the Targeting, Reach-by-country and Advertiser groups (except the name), plus `appStoreUrl`, `callToAction` and `objective`, comes from each ad's detail page, read when **Ad details** is on (the default).

#### Advertiser rows (`recordType: "advertiser"`, with Output = Advertisers or Both)

`advertiserName`, `advertiserBusinessId`, `paidBy`, `advertiserCountry`, `advertiserTikTokUsername`, `advertiserTikTokFollowers`, `advertiserTikTokUrl`, `adsFound`, `adsWithVideo`, `firstShown`, `lastShown`, `countriesReached`, `totalAdReachMin`, `totalAdReachMax` (the sum of each ad's unique-user range — one person who saw three ads counts three times, so use it to rank advertisers, not as a head count), `largestAdReach`, `landingDomains`, `appStoreUrls`, `callToActions`, `objectives`, `categories` (with counts), `sampleAdIds`, `sampleAdTexts`, `advertiserLibraryUrl` (all their ads on TikTok's site), plus the search fields `query`, `queryType`, `searchedRegions`, `dateFrom`, `dateTo`, `scrapedAt`, `error`.

Advertiser rows summarize the ads each search term found: an ad found by two terms counts for the first one only, and the few ads with neither an advertiser name nor a business ID (8 of 300 in a test in France) belong to no advertiser row.

#### Top Ads (`recordType: "topAd"`)

`adId`, `adTitle`, `brandName`, `industry`, `industryGroup`, `objective`, `objectives`, `countries`, `ctrRank` ("Top 25%", as Creative Center shows it) and `ctrTopPercent` (25 — lower is better), `likes`, `comments`, `shares`, `budgetLevel` (Low, Medium, High), `videoUrl`, `videoUrlExpiresAt`, `videoDurationSec`, `videoWidth`, `videoHeight`, `coverUrl`, `landingPage`, `landingDomain`, `source`, `retentionCurve` and `ctrCurve` (`[{second, value}]`, with Analytics on), `analyticsStatus`, `creativeCenterUrl`, `country`, `period`, `sortBy`, `detailStatus`, `query`, `scrapedAt`, `error`.

#### Sample output

A real ad row (trimmed) from a test run on 2026-10-01 (UTC), advertiser search `NIKE Retail B.V.`, all countries, last 90 days:

```json
{
  "recordType": "ad",
  "adId": "1875934571618481",
  "advertiserName": "NIKE Retail B.V.",
  "advertiserBusinessId": "6876453864464188162",
  "paidBy": "INITIATIVE MEDIA B.V.",
  "advertiserCountry": "Netherlands",
  "advertiserTikTokUsername": "nike",
  "advertiserTikTokFollowers": 9300000,
  "adText": "Y2K vibes are back with Nike P-6000. Get styled for the circuit.",
  "adFormat": "video",
  "landingDomain": "nike.com",
  "callToAction": "Shop now",
  "objective": "Traffic",
  "category": "Apparel & Accessories",
  "firstShown": "2026-10-01",
  "lastShown": "2026-10-01",
  "uniqueUsersSeen": "300K-400K",
  "reachByCountry": [
    { "country": "NL", "uniqueUsers": "319K", "uniqueUsersMin": 319000, "uniqueUsersMax": 319000,
      "byAgeAndGender": [{ "age": "18-24", "gender": "FEMALE", "uniqueUsers": "159K" }, { "age": "25-34", "gender": "FEMALE", "uniqueUsers": "118K" }] }
  ],
  "targetCountries": ["NL"],
  "targetAgeGroups": [{ "country": "NL", "ages": ["18-24", "25-34", "35-44"] }],
  "targetGenders": [{ "country": "NL", "genders": ["female"] }],
  "targetAudienceSize": "1.3M-1.6M",
  "targetInterests": ["Sports & Outdoors"],
  "customAudience": false,
  "adLibraryUrl": "https://library.tiktok.com/ads/detail/?ad_id=1875934571618481",
  "detailStatus": "ok"
}
```

An advertiser row (trimmed) from a keywordless search on 2026-10-01 (Germany, last 30 days, sorted by reach):

```json
{
  "recordType": "advertiser",
  "advertiserName": "McDonald's Deutschland Inc.",
  "advertiserBusinessId": "6876493954288714497",
  "paidBy": "OMD München GmbH",
  "advertiserCountry": "Germany",
  "advertiserTikTokUsername": "mcdonaldsde",
  "advertiserTikTokFollowers": 259900,
  "adsFound": 1,
  "firstShown": "2026-08-26",
  "lastShown": "2026-09-07",
  "countriesReached": ["DE"],
  "totalAdReachMin": 1000000,
  "totalAdReachMax": 10000000,
  "largestAdReach": "1M-10M",
  "landingDomains": ["mcdonalds.com"],
  "objectives": [{ "value": "Reach", "count": 1 }]
}
```

### Input & filters

| Input | What it does | Default |
|---|---|---|
| `mode` | `library` (Ad Library) or `topAds` (Creative Center Top Ads) | `library` |
| `searchTerms` | Keywords, advertiser names, or library.tiktok.com links (a search, an advertiser or one ad). One search per line. **Empty = the ads shown** in the chosen countries and period (TikTok lists up to 5,000). Put a keyword in double quotes for the exact phrase (`"nike air max"`); without quotes TikTok matches ads containing any of the words | — |
| `searchBy` | `keyword` or `advertiser` (the name is matched to TikTok's advertiser list; the match and other candidates are in the `SOURCE_REPORT`) | `keyword` |
| `countries` | `all` or any of 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 | `all` |
| `datePreset`, `dateFrom`, `dateTo` | Last 7 / 30 / 90 / 180 / 365 days, or custom dates | last 30 days |
| `adStatus` | `all`, `active`, `inactive` (TikTok's own site shows only active ads by default) | `all` |
| `adFormat` | `all`, `video`, `image`, `text` | `all` |
| `sortBy` | Last shown, published date, or unique users (reach), each ascending or descending — for advertiser searches, exact phrases and searches without a term; unquoted keyword searches come mostly in TikTok's relevance order | last shown, newest first |
| `maxAdsPerQuery` | Ads per search term, up to 5,000. The form starts at 10 | 100 |
| `includeDetails` | Targeting, reach by country/age/gender, payer, registered country, TikTok account, landing page, CTA, objective | on |
| `output` | `ads`, `advertisers` (one row each), or `both` | `ads` |
| `topAdsCountries`, `topAdsPeriod`, `topAdsSortBy` | Top Ads country list (28), last 7 / 30 / 180 days, ranking | US, 30 days, For you |
| `topAdsObjectives`, `topAdsIndustries`, `topAdsLanguages` | Filters (empty = all) | — |
| `maxTopAds` | Top Ads per country. The form starts at 10 | 100 |
| `sweepFilters` | Collect beyond TikTok's 20 ads per filter combination | on |
| `includeTopAdDetails`, `includeTopAdAnalytics` | Landing page, comments, shares, countries · retention and CTR curves | on · off |
| `onlyNewAds`, `monitorName` | Deliver only ads earlier runs (same monitor name) did not deliver | off |
| `proxyConfiguration` | Not needed: the Actor starts with Apify's own IP and switches to Apify residential proxy by itself if TikTok limits it. A proxy set here is always used for the Ad Library | none |

Values outside the lists (a country outside the library, for example) are refused by the input form before the run starts. Other invalid input stops the run before any request, with the reason in the status message (for example `dateFrom (2026-09-20) is after dateTo (2026-09-01).`).

**Each ad once per run.** An ad found by two search terms is delivered and charged once; the later term counts it as a duplicate in the `SOURCE_REPORT`. The same goes for Top Ads in several countries: an ad that is a Top Ad in the US and in Germany is delivered once, under the first country whose search reached it (`country`), and its `countries` field (filled when Top Ad details are on, the default) lists every country it runs in — filter on `countries` to see each country's full list. If Apify moves a run to another server mid-way, the run continues without delivering or charging any ad twice.

### Example inputs (copy & paste)

**1. A competitor's ads with targeting and reach (one advertiser, all countries, last 90 days)**

```json
{ "mode": "library", "searchTerms": ["NIKE Retail B.V."], "searchBy": "advertiser", "datePreset": "last90", "maxAdsPerQuery": 200 }
```

**2. The biggest TikTok advertisers in Germany this month (one row per advertiser, no keyword)**

```json
{ "mode": "library", "searchTerms": [], "countries": ["DE"], "datePreset": "last30", "sortBy": "reachHigh", "maxAdsPerQuery": 300, "includeDetails": false, "output": "advertisers" }
```

**3. Every ad mentioning an exact product name in France and Spain**

```json
{ "mode": "library", "searchTerms": ["\"nike air max\""], "countries": ["FR", "ES"], "datePreset": "last30", "maxAdsPerQuery": 100 }
```

**4. Top Ads inspiration in the US, with retention curves**

```json
{ "mode": "topAds", "topAdsCountries": ["US"], "topAdsPeriod": "30", "maxTopAds": 50, "includeTopAdAnalytics": true }
```

**5. Weekly watch: only new ads of two brands (schedule this input)**

```json
{ "mode": "library", "searchTerms": ["adidas", "puma"], "datePreset": "last30", "maxAdsPerQuery": 200, "onlyNewAds": true, "monitorName": "sportswear" }
```

### Use cases

- **Competitor creative research**: a brand's ads in Europe (up to 5,000 per search term), with copy, video, landing page, CTA and how many people each ad reached per country.
- **Targeting intelligence**: which ages, genders and countries a competitor targets, audience sizes, interests and whether they use custom audiences.
- **New-business leads for agencies and ad-tech**: the biggest TikTok advertisers in a country, their landing domains, TikTok accounts and the agency that pays for their ads.
- **Brand protection**: ads using your brand name in their text, by any advertiser, including removed ads with TikTok's reason and the countries where they were removed.
- **Creative inspiration**: Creative Center Top Ads per country and industry, with likes, CTR rank and retention and CTR curves.
- **Market monitoring**: scheduled runs with only new ads per brand or category.

### Performance & throughput

Test runs on the Apify platform on 2026-10-01, default memory (1 GB), no proxy set in the input:

| Input | Rows | Time | Peak memory |
|---|---|---|---|
| Form default (`nike`, 10 ads with details) | 10 ads | 24 s | 289 MB |
| One advertiser, 1,000 ads with details (NIKE Retail, 90 days) | 1,000 ads (997 with details) | 19 min | 310 MB |
| Two keywords, 150 ads each with details (`"CRM"`, `"temu"`) | 300 ads + 98 advertiser rows | 7.7 min | 456 MB |
| Biggest advertisers in Germany (300 ads, no details) | 222 advertiser rows | 3.7 min | 279 MB |
| Keyword `temu`, 1,000 ads without details | 1,000 ads | 5.2 min | 227 MB |
| Keyword `temu`, maximum 5,000, without details | 4,440 ads (the end of TikTok's list) | 27 min | 239 MB |
| Top Ads, 5 countries × 100, with details | 380 ads | 3 min | 176 MB |
| Top Ads, US, with retention and CTR curves | 124 ads | 1.5 min | 179 MB |

Ad details are the slow part: TikTok allows only a few detail pages per session, so the Actor opens a new browser session every three ads (and moves to Apify residential proxy when TikTok limits the IP). Turn **Ad details** off for a fast list, or use Output = Advertisers with Ad details off, which reads one detail page per advertiser. 1 GB of memory is enough for every run above.

### Integrations

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('foxlabs/tiktok-ads-scraper').call({ mode: 'library', searchTerms: ['adidas'], countries: ['DE'], maxAdsPerQuery: 50 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("foxlabs/tiktok-ads-scraper").call(run_input={"mode": "topAds", "topAdsCountries": ["GB"], "maxTopAds": 30})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Works with Make, n8n, Zapier and the Apify MCP server like any Apify Actor.

### Data quality

What TikTok publishes, as measured on 2026-10-01:

- **Who paid (`paidBy`)**: TikTok sometimes returns the advertiser's own name instead of the paying agency for the same ad (25 repeated reads of two ads with an agency payer: 5 times). Advertiser rows prefer an agency payer when any of the advertiser's ads shows one.
- **Turkey**: TikTok publishes targeting (ages, genders, audience size) but no reach numbers for ads shown in Turkey; those fields stay `null`.
- **Ad spend** is not published in the EU library (0 of 335 ads had a value), so this Actor has no spend field.
- **No creative**: some catalog ads have neither video nor images in the library; `adFormat` is then `null`.
- **Keyword search** matches ads containing any of the words; use double quotes for an exact phrase.
- **Advertiser search** uses TikTok's advertiser suggestions: the exact name wins; otherwise the suggested advertiser with the most ads in your period (for `nike`, TikTok suggests NIKE COM SRL first, with no ads in the last 30 days, and NIKE Retail B.V. second). Every candidate and its ad count is in the `SOURCE_REPORT`.
- **Reach of new ads** often starts low until TikTok updates it: of ads first shown in the last two days, 83-85% showed `0-1K` in two keyword tests with many small advertisers, 42% for NIKE Retail.
- **Top Ads without a login**: TikTok shows 20 ads per filter combination and hides keyword search; the sweep merges combinations (US, 30 days: 124 of the 129 ads TikTok lists, from 49 combinations). `brandName` is often empty in Creative Center itself.
- **No landing page**: many sales video ads with a "Shop now" button have none in the library (their detail page has no link); app ads link to an app store (`appStoreUrl`) instead.

Share of rows with a value, measured on the Apify platform on 2026-10-01:

| Field | One big brand, 1,000 ads (NIKE Retail, 90 days) | 300 keyword ads, many small advertisers (`"CRM"`, `"temu"`) |
|---|---|---|
| Advertiser name, first/last shown, unique users | 100% | 99-100% |
| Business ID, who paid, registered country | 99.7% | 98-100% |
| Reach by country · targeting (countries, ages, genders, audience size) | 99.7% | 99-100% |
| Reach by age and gender | 86% | 79% |
| Landing URL | 66% | 51% |
| Call to action · objective | 86% · 86% | 46% · 79% |
| Video or image | 54% (catalog ads have none) | 100% |
| TikTok account of the advertiser | 90% | 15% |
| Interests | 20% | 6% |

Advertiser rows, biggest advertisers in France (221 rows): name, business ID, payer, registered country and countries reached 100% · landing domain or app store link 80% · CTA 85% · TikTok account 59%. Top Ads (380 ads, 5 countries): title, video, CTR rank, likes, comments, shares, objectives, countries 99.5-100% · industry 95% · landing page 71% · brand 19%.

### Pricing

Pay per event, only for delivered rows:

| Event | When |
|---|---|
| `ad` | each Ad Library ad row |
| `ad-details` | the ad row also carries its detail page (targeting, reach by country, payer…) |
| `advertiser` | each advertiser row |
| `top-ad` | each Top Ads row (detail included) |
| `top-ad-analytics` | the Top Ads row also carries retention and CTR curves |

Status rows (a search with no ads, an unknown advertiser, a failed source) are never charged. Prices are on the Pricing tab.

### FAQ

**Do I need a TikTok account or cookies?** No.

**Which countries does the Ad Library cover?** The 30 EU/EEA countries, Switzerland, the United Kingdom and Turkey — it is TikTok's ad repository for the EU Digital Services Act, extended to those three countries. US ads are not in it; use Top Ads mode for US creative inspiration.

**How far back?** TikTok keeps an ad for one year after it was last shown.

**Why does my keyword return unrelated ads?** TikTok matches any of the words. Put the term in double quotes for the exact phrase.

**Can I search by advertiser business ID?** Not alone — TikTok applies the ID only together with the advertiser's exact name. Use `searchBy: "advertiser"` with the name, or paste the `advertiserLibraryUrl` of an advertiser row.

**Why do the video links stop working?** TikTok signs them for a few hours; `mediaExpiresAt` / `videoUrlExpiresAt` tell you when. Download soon after the run.

**How does monitoring work?** With `onlyNewAds`, delivered ad IDs are remembered per search term, countries and filters in a key-value store in your account named after `monitorName`. The next run skips them.

**What is `ctrRank`?** Without a login, Creative Center shows where an ad's CTR ranks, not the rate itself: "Top 25%" means the ad is in the best quarter. `ctrTopPercent` is the same number (25), lower is better. `budgetLevel` is Creative Center's budget label (Low, Medium, High).

### Troubleshooting

- **A search ends with a `status` row**: read its `error` — e.g. no ads in that period and country, an advertiser name TikTok does not know, or a business ID alone.
- **Fewer ads than `maxAdsPerQuery`**: TikTok had fewer, or lists at most 5,000 results for a keyword search — some of them twice, so a full keyword search gives fewer different ads (`temu`, 30 days: 4,440); narrow the period or the countries. `endedBy` in the `SOURCE_REPORT` says why each search stopped.
- **Some ads have `detailStatus: "failed"`**: TikTok limits detail pages; the Actor retries in new sessions (through Apify residential proxy once TikTok limits the IP), and an ad whose detail still fails is delivered with its list fields (and not charged as `ad-details`).

### Notes, limits & legal

The Ad Library and Creative Center are public pages TikTok publishes for transparency and for marketers. The Actor reads what anyone can see there without logging in. Advertiser names can be names of people (sole traders); handle personal data according to the GDPR. This Actor is not affiliated with TikTok.

### Support

Questions or a missing field: info@foxlabs.com.tr — or open an issue on the Actor page.

### Changelog

See the Changelog tab (`CHANGELOG.md`).

*Built by foXLabs.*

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/tiktok-ads-scraper/changelog.md

# Actor input Schema

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

**Ad Library**: every ad shown in the EU, EEA, Switzerland, the UK and Turkey, searchable by keyword or advertiser, with targeting, reach by country, age and gender, who paid and the landing page. **Top Ads**: TikTok Creative Center's best-performing ads in 28 countries, with likes, CTR rank, video and (optionally) retention and CTR curves.

## `searchTerms` (type: `array`):

Keywords (searched in ad text and advertiser names), advertiser names, or library.tiktok.com links (a search, an advertiser or one ad). Each line is one search. Leave empty to list the ads shown in the chosen countries and period (TikTok lists up to 5,000) — combine with "Sort by: reach" to find the biggest advertisers.

## `searchBy` (type: `string`):

**Keywords** match ad text and advertiser names. **Advertiser names** are matched to TikTok's advertiser list and return only that advertiser's ads: the exact name wins, otherwise the suggested advertiser with the most ads in the period (every candidate and its ad count is in the SOURCE\_REPORT).

## `countries` (type: `array`):

Where the ads were shown. The library covers the EU, EEA, Switzerland, the UK and Turkey only (TikTok publishes it under the EU Digital Services Act). Leave empty or pick "All covered countries".

## `datePreset` (type: `string`):

Ads shown in this period. TikTok keeps an ad for one year after it was last shown. Choose "Custom dates" to use the two date fields below.

## `dateFrom` (type: `string`):

First day (YYYY-MM-DD). Used only when Period is "Custom dates".

## `dateTo` (type: `string`):

Last day (YYYY-MM-DD). Used only when Period is "Custom dates"; empty = today.

## `adStatus` (type: `string`):

TikTok's own website shows only active ads by default; this Actor returns active and inactive ads unless you choose otherwise.

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

Only ads of this format.

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

Order of the ads for advertiser searches, exact phrases and searches without a term (it also decides which ads you get when there are more than your maximum). Unquoted keyword searches come mostly in TikTok's relevance order. "Reach" = unique users who saw the ad.

## `maxAdsPerQuery` (type: `integer`):

Stop after this many ads for each search term (at most 5,000).

## `includeDetails` (type: `boolean`):

Open each ad's detail page: targeting (age, gender, countries, audience size, interests, custom audiences), unique users by country, age and gender, who paid, the advertiser's registered country and TikTok account, landing page, call to action and objective. Billed as an extra "ad-details" event per ad that has them. Turn off for a faster, cheaper list.

## `output` (type: `string`):

**Ads**: one row per ad. **Advertisers**: one row per advertiser (ads found, first/last shown, countries reached, summed reach, landing domains, who paid, TikTok account). **Both**: ad rows followed by advertiser rows.

## `topAdsCountries` (type: `array`):

Top Ads are listed per country. One search per country.

## `topAdsPeriod` (type: `string`):

Top Ads of the last 7, 30 or 180 days.

## `topAdsSortBy` (type: `string`):

TikTok's ranking of the Top Ads.

## `topAdsObjectives` (type: `array`):

Only ads with these objectives. Empty = all.

## `topAdsIndustries` (type: `array`):

Only ads from these industries. Empty = all.

## `topAdsLanguages` (type: `array`):

Only ads in these languages. Empty = all.

## `maxTopAds` (type: `integer`):

Stop after this many ads per country.

## `sweepFilters` (type: `boolean`):

Without a TikTok login, Creative Center shows only 20 ads per filter combination. With this on, the Actor also asks for other sort orders, each objective and each industry, and merges the unique ads (no login, no cookies).

## `includeTopAdDetails` (type: `boolean`):

Open each Top Ad's detail: landing page, comments, shares, all objectives and countries, source. Included in the "top-ad" event.

## `includeTopAdAnalytics` (type: `boolean`):

Second-by-second retention curve (share of viewers still watching) and CTR curve for each ad. Billed as an extra "top-ad-analytics" event per ad that has them.

## `onlyNewAds` (type: `boolean`):

Deliver (and charge) only ads that earlier runs with the same monitor name did not deliver. The memory is kept per search term, countries and filters, in a key-value store in your account.

## `monitorName` (type: `string`):

Use a different name for each separate watch list (letters, digits and dashes).

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

Not needed: the Actor starts with Apify's own IP and switches to Apify residential proxy by itself if TikTok limits it (Top Ads first try Apify datacenter proxy). A proxy you set here is always used for the Ad Library.

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

How many ad details are fetched at the same time.

## Actor input object example

```json
{
  "mode": "library",
  "searchTerms": [
    "nike"
  ],
  "searchBy": "keyword",
  "countries": [
    "all"
  ],
  "datePreset": "last30",
  "adStatus": "all",
  "adFormat": "all",
  "sortBy": "newest",
  "maxAdsPerQuery": 10,
  "includeDetails": true,
  "output": "ads",
  "topAdsCountries": [
    "US"
  ],
  "topAdsPeriod": "30",
  "topAdsSortBy": "for_you",
  "topAdsObjectives": [],
  "topAdsIndustries": [],
  "topAdsLanguages": [],
  "maxTopAds": 10,
  "sweepFilters": true,
  "includeTopAdDetails": true,
  "includeTopAdAnalytics": false,
  "onlyNewAds": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxConcurrency": 4
}
```

# Actor output Schema

## `dataset` (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 = {
    "mode": "library",
    "searchTerms": [
        "nike"
    ],
    "maxAdsPerQuery": 10,
    "maxTopAds": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/tiktok-ads-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 = {
    "mode": "library",
    "searchTerms": ["nike"],
    "maxAdsPerQuery": 10,
    "maxTopAds": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/tiktok-ads-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 '{
  "mode": "library",
  "searchTerms": [
    "nike"
  ],
  "maxAdsPerQuery": 10,
  "maxTopAds": 10
}' |
apify call foxlabs/tiktok-ads-scraper --silent --output-dataset

```

## MCP server setup

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