# TikTok Ads Library Scraper: EU Ads, No Login (`automation_craft/tiktok-ads-library-scraper`) Actor

Scrape the TikTok Ad Library (EU Commercial Content Library) by advertiser or keyword across 32 EEA, Swiss and UK markets, no login. Advertiser, first and last shown, reach band, video and image URLs, status, and DSA targeting by country, age and gender on request. JSON, CSV, API. Pay per ad.

- **URL**: https://apify.com/automation\_craft/tiktok-ads-library-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** Marketing, Social media, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 ads

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, No Login

**Scrape the TikTok Ad Library** (TikTok's EU Commercial Content Library at library.tiktok.com) by advertiser name, keyword or pasted URL, in any of the 32 EEA, Swiss and UK markets it serves, with no login, no cookies and no API key. Every ad row carries the advertiser, the ad title, first and last shown dates, the reach band TikTok publishes ("Unique users seen"), status and rejection notes, and the video and image URLs. Turn on ad details and each ad also gets the Digital Services Act block: reach by country, age and gender, and the targeting the advertiser declared.

You pay per ad delivered. Duplicates, ads your dedup memory already knows, query summaries, status rows, refused pages and empty runs cost nothing.

### Quick start

1. Open the Actor and type advertiser names or keywords into **Advertiser names, keywords or Ad Library URLs**, one per line, exactly as you would in the Ad Library search box (`nike`, `adidas`). You can also paste any `library.tiktok.com/ads?...` URL; its region, dates and filters are applied to that query.
2. Pick one or more **Ad target countries**. The library only serves EEA, Swiss and UK markets, because it exists under the EU Digital Services Act.
3. Set **Max ads per query** and **Max ads (total)**. Leave both at 0 for everything the library serves.
4. Tick **Fetch ad details** if you want reach by country, age and gender and the declared targeting on every ad (8.00 per 1,000 detail records, see the pricing section for the speed it runs at).
5. Run it. Download the **Ads** view as JSON, CSV or Excel, read the **Query summaries** view for the totals TikTok reported, or read the dataset through the API.
6. For a weekly competitor watch, give the run a **Dedup memory name** and schedule it: every later run returns only ads it has not delivered yet, and known ads are never charged again.

### What you get

#### Ad rows (`type: "ad"`)

Measured on 846 ads from 17 platform runs on 2026-09-22 (advertiser name 99%, title 85%, first and last shown 100%, reach band 100%, video URLs 90%, image URLs 77%, rejection reasons 1%; on the 29 ads with details: landing URL 59%, call to action 79%, objective 100%, reach by region 100%).

| Field | What it is |
|---|---|
| `adId`, `libraryUrl` | TikTok's id and the public detail page |
| `advertiserName` | the legal entity name shown on the ad |
| `title` | the ad text TikTok shows as the title |
| `firstShown`, `lastShown`, `daysShown` | ISO 8601 dates and the inclusive day count between them |
| `region` | the target country the query ran in |
| `estimatedAudience`, `estimatedAudienceMin`, `estimatedAudienceMax` | the reach band as printed ("1K-10K") and parsed to numbers |
| `impressions` | the impression figure TikTok publishes on the row (0 for most commercial ads) |
| `auditStatus`, `auditStatusCode`, `sorAuditStatus` | approved, rejected, pending or approved-after-appeal, plus TikTok's raw codes |
| `adType`, `showMode` | TikTok's content type and display mode codes |
| `videoUrls`, `videoCovers`, `imageUrls` | signed CDN URLs of the creative (they expire, fetch what you want to keep) |
| `rejectionReasons`, `rejectionInfo` | TikTok's printed reasons when an ad was removed |
| `hasDetails`, `externalUrl`, `callToAction`, `advertisingObjective`, `subject` | the detail block headline fields (with **Fetch ad details**) |
| `targeting` | reach by country with age and gender breakdowns (`reachByRegion[]`, bands parsed to numbers) and every targeting parameter the advertiser declared (locations, languages, interests, devices, operating systems, spending power) |
| `advertiser` | the advertiser block when TikTok publishes it |
| `query`, `shard`, `isNew`, `scrapedAt` | which query and date window surfaced the ad; `isNew` is always true for delivered rows |

#### Query summary rows (`type: "query-summary"`), one per query x region, free

`totalReported` is the count TikTok printed for the query, `capReached` says whether it hit TikTok's 5,000 row limit, `shards` and `pagesFetched` say how much work it took, `adsDelivered`, `knownSkipped`, `detailsDelivered` and `detailsRefused` say what you got, and `stopReason` is one of `complete`, `max-ads-per-query`, `max-ads-reached`, `charge-limit`, `end-of-results` or `blocked`.

#### The run summary (`type: "summary"`), free

Counters for queries, pages, page loads and their time, ads seen, delivered and charged, duplicates and known ads skipped, details delivered and refused, refused pages, and billing counters that report attempted and platform confirmed charges separately.

### How much does it cost to scrape the TikTok Ad Library?

Live prices at the BRONZE tier; Silver 10 percent and Gold 20 percent off the result events, no discount on the Actor start event.

| Event | Price | When it is charged |
|---|---|---|
| Ad | $1.00 per 1,000 | once per unique ad delivered |
| Ad detail record | $8.00 per 1,000 | once per ad that carries the DSA detail block |
| Actor start | $2.00 per run per GB of memory | once per run; a 1 GB run pays it once |

The Store pricing card shows these same prices per 1,000 events: "$1.00 / 1,000" on the Ad row means one ad costs a tenth of a cent, and "$8.00 / 1,000" on the Ad detail record row means one detail record costs 0.8 cents. A query that delivers 500 ads costs 500 x $1.00 / 1,000 plus the start event, about $0.50. Adding details to all 500 adds 500 x $8.00 / 1,000, about $4.00; the detail record is priced for the page reloads it costs (see below).

Measured platform cost on 8 runs without details: about $0.114 per 1,000 ads on the default 1 GB memory with the datacenter proxy (the price is $1.00 per 1,000).

**About detail speed.** TikTok opens its detail endpoint for some page loads and refuses it for others (measured on Apify: about one load in three is open, and an open load serves every detail read made on it). The Actor reads details while a load is open and reloads the query page on the first refusal, up to six times per page; a refused record is never charged. Expect roughly 2 ads with details per minute per worker; a run without details reads about 50 ads per minute per worker. Set **Max detail records** to keep a big run fast and cheap.

### Input

| Field | Type | Notes |
|---|---|---|
| `queries` | array | advertiser names, keywords or pasted library.tiktok.com URLs (an `ads/detail/?ad_id=` URL fetches that one ad) |
| `regions` | array | EEA, Swiss and UK ISO codes or names; `all` for every market |
| `adIds` | array | ad ids to fetch directly |
| `advertiserIds` | array | TikTok business ids (`adv_biz_ids`) to restrict every query to |
| `lastShownAfter`, `lastShownBefore` | date | the "last shown" window, default the last year |
| `adType` | 0, 1 or 2 | TikTok's content type filter; 0 keeps everything |
| `gender` | ALL, MALE, FEMALE | the audience gender filter |
| `maxAdsPerQuery`, `maxAds` | integer | caps, 0 = no cap |
| `includeDetails`, `maxDetails` | boolean, integer | the DSA detail block and how many ads get it |
| `dedupMemoryName`, `resetDedupMemory` | string, boolean | cross run memory |
| `proxyConfiguration`, `maxConcurrency` | object, 1 to 3 | Apify datacenter proxy by default; parallel query workers |

```json
{
  "queries": ["nike"],
  "regions": ["ES", "DE"],
  "maxAdsPerQuery": 200,
  "includeDetails": true,
  "maxDetails": 50,
  "dedupMemoryName": "nike-eu-watch"
}
```

### What this Actor does NOT do

- It does not cover ads shown outside the EEA, Switzerland and the UK. TikTok's Ad Library is the company's Digital Services Act transparency surface and only holds ads targeted at those markets. Worldwide Top Ads live in the Creative Center (see the sibling Actor below).
- It does not report ad spend. TikTok publishes reach bands, never money; rows carry `estimatedAudience`, not a spend figure.
- It does not host videos or images. Media URLs are signed CDN links that expire; download what you want to keep.
- It does not sort by anything other than last shown date (newest first) or filter by age band or reach band. TikTok's API rejects those parameters for anonymous visitors, so they are not offered rather than silently ignored.
- It does not go past TikTok's 5,000 rows per query on its own terms; it splits the date window automatically and the query summary says when a shard still reported the cap.

### FAQ

#### Do I need a TikTok account, cookies or an API key?

No. The Ad Library is a public page and this Actor reads it the way a signed-out visitor does, through a headless browser that TikTok issues its access token to. Nothing in the input asks for a credential.

#### Which countries does the TikTok Ad Library cover?

The 27 EU member states plus Iceland, Liechtenstein, Norway, Switzerland and the United Kingdom, 32 markets in total. TikTok publishes the library under the EU Digital Services Act, so ads shown only outside those markets are not in it.

#### Does the TikTok Ad Library show ad spend?

No. TikTok publishes a reach band per ad ("Unique users seen", for example 1K-10K) and, in the detail block, that band by country, age and gender. This Actor delivers the band as printed and parsed to numbers; it does not invent a spend figure.

#### How many ads can one query return?

TikTok caps every query at 5,000 rows and serves 12 per page. When a query hits the cap the Actor splits the date window in half and reads the halves, down to single days, and the query summary reports whether any shard still hit the cap.

#### Why are ad details slower than ads?

TikTok opens its detail endpoint for some page loads and refuses it for others, so the Actor reads details while a load is open and reloads the query page on the first refusal, up to six times per page. Details that TikTok refuses are never charged.

#### How do I get only the ads that are new since last week?

Put a name in dedupMemoryName and use the same name every run. Ads already delivered under that name are skipped free of charge.

#### Why does this Actor run with limited permissions?

Least privilege. It can only reach its own storages: the dataset it writes and the one named key-value store it creates for your dedup memory. It cannot read anything else in your Apify account.

### More data tools by Automation Craft

- [TikTok Creative Center Scraper: Top Ads, No Login](https://apify.com/automation_craft/tiktok-creative-center-scraper)
- [Meta Ad Library Scraper - All Placements, Filters](https://apify.com/automation_craft/meta-ads-library-scraper)
- [Facebook Ads Library Scraper - Page Ads, No Login](https://apify.com/automation_craft/facebook-ads-library-scraper)
- [Instagram Ads Library Scraper - Creatives, Video](https://apify.com/automation_craft/instagram-ads-library-scraper)
- [LinkedIn Ad Library Scraper: Ads by Company](https://apify.com/automation_craft/linkedin-ad-library-scraper)
- [Google Trends Scraper](https://apify.com/automation_craft/google-trends-scraper)

### Changelog

- 0.1.0 (2026-09-23): first release.

# Actor input Schema

## `queries` (type: `array`):

One per line: an advertiser name or keyword exactly as you would type it into the Ad Library search box (for example "nike"), or a pasted library.tiktok.com URL (its region, dates and filters are applied to that query; an ads/detail URL fetches that one ad). Leave empty with a region set to list every ad shown in that country.

## `regions` (type: `array`):

The EEA, Swiss and UK markets the Ad Library serves (the EU Digital Services Act scope). Pick several to run every query in each. Through the API pass ISO codes or names, or "all" for every market.

## `adIds` (type: `array`):

Ad Library ad ids to fetch directly (the number in library.tiktok.com/ads/detail/?ad\_id=...). Each returns the current record of that ad with its detail block when "Fetch ad details" is on. Unknown ids are reported and free.

## `advertiserIds` (type: `array`):

TikTok business ids (adv\_biz\_ids in an Ad Library URL) to restrict the search to those advertisers. Combined with every query and region.

## `lastShownAfter` (type: `string`):

Start of the "last shown" window (YYYY-MM-DD). Default: one year back, the most the library keeps.

## `lastShownBefore` (type: `string`):

End of the window (YYYY-MM-DD). Default: today.

## `adType` (type: `string`):

TikTok's ad\_type filter: 0 keeps every ad, 1 and 2 are the two content types the library distinguishes (each row carries its adType). Measured on one advertiser: 685 ads in total, 336 of type 1.

## `gender` (type: `string`):

Keep ads whose declared audience gender matches. ALL keeps every ad.

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

Cap per query x region. 0 means everything the library serves. One query is capped at 5,000 rows by TikTok; the Actor splits the date window automatically to get past it.

## `maxAds` (type: `integer`):

Hard cap on delivered, charged ads for the whole run. 0 means no cap.

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

Adds the "Ad details" block to each ad: unique users seen by country, age and gender, the targeting the advertiser declared (locations, languages, interests, devices), landing URL, call to action, objective and subject. $8.00 per 1,000 detail records delivered. TikTok opens the detail endpoint for some page loads and refuses it for others, so the Actor reads details while a load is open and reloads the query page on the first refusal (up to six reloads per page): expect a few ads with details per minute per worker, and set a cap below.

## `maxDetails` (type: `integer`):

Cap on ads that get the detail block (the rest are delivered without it). 0 means every delivered ad.

## `dedupMemoryName` (type: `string`):

Name this monitor, for example "competitor-watch". Ads delivered under that name are remembered in a key-value store the Actor creates in your account and are never delivered or charged again. Schedule the run and you have a change feed.

## `resetDedupMemory` (type: `boolean`):

Forget everything stored under the memory name before running.

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

Leave the default (Apify datacenter proxy). The Ad Library token is bound to the exit IP, so each worker keeps one sticky session; a refused exit is retired automatically.

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

How many query x region jobs run at the same time, each in its own browser context on its own exit IP. 2 fits the default memory; 3 needs 2 GB.

## Actor input object example

```json
{
  "queries": [
    "nike"
  ],
  "regions": [
    "ES"
  ],
  "adType": "0",
  "gender": "ALL",
  "maxAdsPerQuery": 24,
  "maxAds": 24,
  "maxDetails": 0,
  "resetDedupMemory": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 2
}
```

# Actor output Schema

## `ads` (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 = {
    "queries": [
        "nike"
    ],
    "regions": [
        "ES"
    ],
    "maxAdsPerQuery": 24,
    "maxAds": 24,
    "includeDetails": false,
    "dedupMemoryName": "",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/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 = {
    "queries": ["nike"],
    "regions": ["ES"],
    "maxAdsPerQuery": 24,
    "maxAds": 24,
    "includeDetails": False,
    "dedupMemoryName": "",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/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 '{
  "queries": [
    "nike"
  ],
  "regions": [
    "ES"
  ],
  "maxAdsPerQuery": 24,
  "maxAds": 24,
  "includeDetails": false,
  "dedupMemoryName": "",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation_craft/tiktok-ads-library-scraper --silent --output-dataset

```

## MCP server setup

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