# TikTok Ads Library Scraper - EU Ads, Targeting & Top Ads (`scrapewise/tiktok-ads-library-scraper`) Actor

Scrape the TikTok Ad Library (EU, EEA, UK, Switzerland, Turkey) by keyword, advertiser, country and dates: advertiser, video, first and last shown, audience, plus landing page, targeting and impressions per country. Top Ads mode adds US best performers with CTR. Error rows are free.

- **URL**: https://apify.com/scrapewise/tiktok-ads-library-scraper.md
- **Developed by:** [Scrapewise Data](https://apify.com/scrapewise) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.02 / 1,000 ad delivereds

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 Ads Library Scraper: EU ads by keyword or advertiser, with targeting, landing pages and Top Ads

TikTok Ads Library Scraper collects **ads from TikTok's public Ad Library** (the Commercial Content Library that
TikTok keeps for the EU, the EEA, Switzerland, the UK and Turkey), without a TikTok account, cookies or a browser.
Search by keyword or advertiser name, pick a country and a date range, and each ad comes back as one clean row: the
advertiser, the ad text, the first and last day it was shown, the estimated audience, the video and images. Turn on
details to add the landing page, the call to action, the campaign objective, the advertiser's country, business id
and TikTok account, who paid for the ad, impressions per country and the targeting (age, gender, audience size,
interests).

A second mode reads the **Creative Center Top Ads** gallery: TikTok's own list of best-performing ads for the United
States and 27 more countries, with CTR, likes, industry, objective, the video in up to 1080p and the landing page.

It is used for competitor research and ad spying, for finding winning creatives and hooks in a niche, for following
what a brand runs in Europe week by week, for agency pitch decks, and for building ad datasets for AI and analytics.

### At a glance

| What | Price |
|---|---|
| Ad delivered (Ad Library or Top Ads) | **US$ 1.20 per 1,000 ads** (US$ 0.0012 each) |
| Ad details (only with `includeDetails` on) | US$ 1.00 per 1,000 ads (US$ 0.001 each) |
| Run start | US$ 0.005 per run |

- 100 ads without details = **US$ 0.125**. 100 ads with details = **US$ 0.225**.
- Error rows, duplicates and ads from other advertisers skipped by the advertiser filter are never charged. The
  details charge only applies to ads whose detail was actually added.
- `maxItems` is a hard cap per search, and a spending limit set on the run stops it cleanly with everything delivered
  so far.
- Speed: about 50 ads in 6 seconds without details; with details about 1 to 2.5 seconds per ad.

### Quick start

Ads that mention a keyword in all covered countries, shown in the last 30 days:

```json
{
  "searchTerms": ["skincare"],
  "maxItems": 50
}
```

One advertiser in Germany over the last 90 days, with landing pages and targeting:

```json
{
  "advertisers": ["Nike"],
  "country": "DE",
  "lastDays": 90,
  "includeDetails": true,
  "maxItems": 100
}
```

Top Ads in the United States, ranked two ways, with landing pages:

```json
{
  "mode": "topAds",
  "topAdsCountries": ["US"],
  "topAdsSortBy": ["for_you", "ctr"],
  "topAdsPeriod": "30",
  "includeDetails": true
}
```

### Input

| Field | What it does |
|---|---|
| `mode` | `library` (default): the Ad Library. `topAds`: the Creative Center Top Ads gallery. |
| `searchTerms` | Keywords, one per line. TikTok matches the ad text and the advertiser name. Each keyword is searched in each country. |
| `advertisers` | Advertiser names, one per line (see "How the advertiser search works" below). |
| `country` | A covered country code (`DE`, `FR`, `GB`, `ES`, `IT`, `NL`, `PL`, `SE`, `TR`...) or `all` (default). |
| `lastDays` | Ads shown at any time in the last N days (default 30). |
| `startDate`, `endDate` | Exact date range (YYYY-MM-DD, UTC). `startDate` wins over `lastDays`. |
| `includeDetails` | Adds the detail fields listed below (default off). |
| `maxItems` | Cap for each keyword or advertiser and country (Top Ads: for each country). Default 50; 0 = as many as the source gives. |
| `topAdsCountries` | Top Ads countries (default `US`). |
| `topAdsPeriod` | `7`, `30` (default) or `180` days. |
| `topAdsSortBy` | One or more rankings: `for_you`, `like`, `ctr`, `impression`, `play_2s_rate`, `play_6s_rate`, `cvr`. |
| `topAdsIndustries` | Optional industries, for example `Beauty & Personal Care`, `Apps`, `Games`, `Food & Beverage`. |
| `topAdsObjectives` | Optional objectives: `traffic`, `app_installs`, `conversions`, `video_views`, `reach`, `lead_generation`, `product_sales`. |
| `proxyConfiguration` | Apify datacenter proxy by default. |

`query`, `keyword`, `searchQuery`, `searchQueries`, `advertiser`, `countries`, `days`, `dateFrom`, `dateTo`,
`fetchDetails`, `maxResults` and `limit` are accepted too, so inputs written for other TikTok ads tools keep working.
`countries` takes a list, to search several countries in one run.

### Output

**Ad Library row** (`type: ad`):

| Field | What it is |
|---|---|
| `adId`, `adUrl` | Ad id and its page in the TikTok Ad Library |
| `advertiserName` | Advertiser as registered with TikTok |
| `adTitle` | Ad text |
| `firstShownDate`, `lastShownDate`, `daysShown` | First and last day the ad was shown (UTC) and the days between them |
| `estimatedAudience` | Unique users reached, as a range (`10K-100K`) |
| `hasVideo`, `videoUrl`, `videoUrls` | The ad video (mp4) |
| `coverImageUrl`, `imageUrls` | Cover frame and images of the ad |
| `country`, `searchQuery`, `advertiserFilter` | The search that found the ad |

**With `includeDetails`**, the same row also has:

| Field | What it is |
|---|---|
| `landingPageUrl`, `landingDomain` | Where the ad sends people, with the UTM tags as published |
| `callToAction`, `objective`, `subject` | Button text (`Shop now`), campaign objective (`Traffic`, `Sales`, `Reach`...) and topic when TikTok shows one (`Health`, `Food & Beverage`) |
| `advertiserCountry`, `advertiserBusinessId` | Country where the advertiser is registered and TikTok's business id |
| `sponsor` | Who paid for the ad (often a media agency) |
| `tiktokUsername`, `tiktokDisplayName`, `tiktokProfileUrl`, `tiktokFollowers`, `tiktokFollowersText`, `tiktokAccountType` | The TikTok account that ran the ad, when the advertiser linked one |
| `totalImpressions`, `countriesShown`, `impressionsByCountry` | Impressions in total and per country, as TikTok publishes them |
| `targetCountries`, `targetAge`, `targetGender`, `targetAudienceSize`, `targetLanguages`, `targetInterests`, `targetOperatingSystems` | Targeting set by the advertiser |
| `usesCustomAudience`, `excludesCustomAudience`, `targetsHighSpendingPower` | Audience switches, `true` or `false` |
| `detailsIncluded` | `true` when the detail was added (and charged); `false` if TikTok refused it after 4 attempts |

Rarer targeting options (provinces, cities, device models, video and creator interactions) appear only on ads that
use them.

**Top Ads row** (`type: topAd`): `adId`, `adUrl` (Creative Center page), `adTitle`, `brandName` (when TikTok
shows it), `objective`, `industry`, `industryId`, `ctr`, `likes`, `videoUrl` (highest quality), `videoUrls` (by
quality, up to 1080p), `videoDurationSeconds`, `videoWidth`, `videoHeight`, `coverImageUrl`, `country`,
`periodDays`, `sortBy`, plus `industryFilter` and `objectiveFilter` when you used them. With `includeDetails`:
`landingPageUrl`, `landingDomain`, `comments`, `shares`, `targetCountries`, `objectives`, `hasVoiceOver`.

One real Ad Library row with details (links and lists shortened):

```json
{
  "type": "ad",
  "source": "library",
  "adId": "1879008267714690",
  "adUrl": "https://library.tiktok.com/ads/detail/?ad_id=1879008267714690",
  "advertiserName": "NIKE Retail B.V.",
  "adTitle": "Trainiere ohne Kompromisse - im Nike Hybrid RN.",
  "firstShownDate": "2026-10-14",
  "lastShownDate": "2026-10-18",
  "daysShown": 5,
  "estimatedAudience": "10K-100K",
  "imageUrls": ["https://p16-common-sign.tiktokcdn.com/ad-site-i18n-sg/..."],
  "landingPageUrl": "https://www.nike.com/de/w/hybrid-training-8wvhh?cp=...",
  "landingDomain": "nike.com",
  "callToAction": "Shop now",
  "objective": "Traffic",
  "advertiserCountry": "Netherlands",
  "advertiserBusinessId": "6876453864464188162",
  "sponsor": "INITIATIVE MEDIA B.V.",
  "tiktokUsername": "nike",
  "tiktokFollowers": 9300000,
  "tiktokAccountType": "VERIFIED_BA",
  "totalImpressions": "10K-100K",
  "impressionsByCountry": [{"country": "DE", "impressions": "76K"}],
  "targetAge": ["18-24", "25-34"],
  "targetGender": ["female", "male", "unknown"],
  "targetAudienceSize": "4.3M-5.2M",
  "targetInterests": "Health & Fitness, Sports & Fitness, Exercise & Fitness, Physical Fitness, Sports",
  "detailsIncluded": true
}
```

### How the advertiser search works

TikTok's own "search by advertiser" returns no ads today for logged-out visitors. So the Actor searches the advertiser
name as a keyword and keeps only ads whose advertiser name contains what you typed (ignoring upper and lower case):
`Nike` keeps `NIKE Retail B.V.` and leaves out a creator who mentions Nike. Skipped ads are not charged. Use the
name as the advertiser appears in the library; a short, distinctive part of it works best. The Actor reads up to 40
pages (480 ads) per advertiser and stops earlier after 8 pages in a row without a match.

### Errors you may see

Every error is a row with `errorCode` and is never charged:

| errorCode | Meaning |
|---|---|
| `INVALID_INPUT` | A field has a wrong value, a country the source does not cover, or an unknown industry |
| `NO_RESULTS` | No ad for this keyword, advertiser, country and dates |
| `REFUSED` | The library refused the search parameters (check the country and the dates) |
| `BLOCKED` | TikTok refused every attempt for this search; run it again in a few minutes |
| `UNEXPECTED` | Something else stopped the run; what was delivered before it stays |

### Integrations, scheduling and AI agents

- **Schedule** the same advertiser or keyword every day or week in
  [Apify schedules](https://docs.apify.com/platform/schedules) with `lastDays: 7` to follow new creatives.
- **Export** as JSON, CSV, Excel or XML, or read the dataset from the [Apify API](https://docs.apify.com/api/v2).
- **Connect** it to Make, n8n, Zapier, Google Sheets or Slack through
  [Apify integrations](https://docs.apify.com/platform/integrations).
- **AI agents:** call it as a tool through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp)
  in Claude, ChatGPT, Cursor or any MCP client, for example "get the last 30 days of TikTok ads for protein powder in
  Germany with landing pages, and group them by advertiser".

### FAQ

**Do I need a TikTok account?** No. Both sources are public pages that TikTok serves without login.

**Why only Europe and Turkey in the Ad Library?** TikTok publishes the library to meet the EU Digital Services Act
and similar rules, so it covers ads shown in the EU, the EEA, Switzerland, the UK and Turkey. An ad that only ran in
the United States is not there. For the US, use Top Ads mode.

**How many ads can one search return?** The library counts up to 5,000 ads per search (the count stops there).
Narrow by country or dates to reach deeper. Top Ads gives 20 ads per country, period, ranking, industry and objective
to logged-out visitors; pick several rankings, industries or objectives for more distinct ads.

**How long do the video links work?** Video and image links are signed by TikTok and expire after about two days.
Download the files you want to keep soon after the run, or run again for fresh links.

**Are impressions and audience exact?** No. TikTok publishes them as ranges (`10K-100K`, `4.3M-5.2M`), and the
Actor keeps them as published.

**Is it legal?** The Actor reads public ad transparency data only. It returns no emails or phone numbers and no
profile pictures. You are responsible for how you use the data under the laws that apply to you.

**Something broke or a field is missing?** Open an issue on the Actor page; issues are answered within a day.

### Limitations

- The Ad Library returns ads from the last year only, and only ads shown in its covered countries.
- Ad spend is not published by TikTok for commercial ads, so there is no spend field.
- With details on, each ad needs one more request, and TikTok sometimes answers "system busy": the Actor waits and
  retries up to 4 times; an ad that still fails is delivered without details and without the
  details charge.
- Top Ads `brandName` is empty for many ads, and some Top Ads have no landing page.

### Changelog

- **19 Oct 2026:** first version: Ad Library by keyword, advertiser, country and dates, optional details with landing
  page, advertiser account, impressions per country and targeting; Creative Center Top Ads mode with rankings,
  industries, objectives and details.

# Actor input Schema

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

Ad Library searches TikTok's public archive of ads shown in Europe and Turkey (keyword, advertiser, dates, country). Top Ads reads the Creative Center gallery of best-performing ads, including the United States, with CTR and likes.

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

Words to search in the Ad Library, one per line, for example skincare, protein powder or vpn. TikTok matches the ad text and the advertiser name. Each keyword is searched in each country. Ad Library only.

## `advertisers` (type: `array`):

Advertiser names, one per line, for example Nike or Temu. The Actor searches the name and keeps only ads whose advertiser name contains it (ads from other advertisers are skipped and not charged). Ad Library only.

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

Country where the ad was shown. The library covers the EU, the EEA, Switzerland, the UK and Turkey. Through the API you can also send a list in countries.

## `lastDays` (type: `integer`):

Ads shown at any time in the last N days (UTC). Ignored when Start date is set.

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

Optional: ads shown on or after this date (YYYY-MM-DD). The library keeps about one year.

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

Optional: ads shown on or before this date (YYYY-MM-DD). Empty = today.

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

Countries for Top Ads mode. Each country returns up to 20 ads per sort order, industry and objective.

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

Time window of the Top Ads ranking.

## `topAdsSortBy` (type: `array`):

One or more rankings. TikTok serves 20 ads per ranking without login, so picking several gives more distinct ads (duplicates are removed and not charged).

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

Optional: only ads from these industries. Each industry is a separate list of up to 20 ads. Empty = all industries.

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

Optional: only ads with these campaign objectives. Each objective is a separate list of up to 20 ads. Empty = all objectives.

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

On: opens each ad's detail for the landing page, call to action, objective, advertiser country and business id, TikTok account and followers, who paid for it, impressions per country and targeting (age, gender, audience size, interests). Takes about 1 to 2 seconds per ad and adds the 'Ad details' charge. Top Ads: landing page, comments, shares, countries and keywords.

## `maxItems` (type: `integer`):

Upper limit of ads for each keyword or advertiser and country (Top Ads: for each country). 0 = as many as the source gives (the library stops at 5,000 per search).

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

Apify datacenter proxy by default. If it is refused several times in a row, the Actor moves to residential proxy on its own.

## Actor input object example

```json
{
  "mode": "library",
  "searchTerms": [
    "skincare"
  ],
  "country": "all",
  "lastDays": 30,
  "topAdsCountries": [
    "US"
  ],
  "topAdsPeriod": "30",
  "topAdsSortBy": [
    "for_you"
  ],
  "includeDetails": false,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsCsv` (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 = {
    "searchTerms": [
        "skincare"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapewise/tiktok-ads-library-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 = {
    "searchTerms": ["skincare"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapewise/tiktok-ads-library-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 '{
  "searchTerms": [
    "skincare"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapewise/tiktok-ads-library-scraper --silent --output-dataset

```

## MCP server setup

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