# TikTok DSA Ads Transparency Library Scraper (`vexaloom-labs/tiktok-dsa-ads-transparency-library-scraper`) Actor

Search TikTok's EU/EEA ad transparency database by keyword, advertiser or ad ID. Get creative media, advertiser identity, impression buckets, audit status and per-region/age/gender targeting.

- **URL**: https://apify.com/vexaloom-labs/tiktok-dsa-ads-transparency-library-scraper.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** Social media, Automation, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 DSA Ads Transparency Library Scraper

Search **TikTok's DSA ad transparency library** across 33 European markets and the global **Creative Center Top Ads** from one actor. Get ad creatives, advertiser identity, first/last shown dates, unique-user reach, age/gender targeting, CTAs, landing pages and Creative Center performance signals — with no TikTok account, cookies, API key or proxy setup.

### What this actor does

- **DSA library search** by keyword, exact advertiser name (optionally with its business ID), ad ID or a pasted library URL — in 33 EU/EEA/UK/CH/TR markets or all of them.
- **Server-side filters** for ad type, active/inactive status, age, gender, unique reach and six sort orders, plus an exact-phrase option.
- **Full ad detail** (optional): caption, CTA, landing page, advertising objective, registered advertiser, sponsor, linked TikTok account, per-country reach and age × gender breakdowns.
- **Creative Center Top Ads** (optional): global markets, 7/30/180-day windows, ranking by For You/CTR/likes, objective/industry/language filters, video renditions, CTR, likes, cost tier and optional landing pages/comments/shares.
- **Both sources in one run**, with a `source` field on every row.
- **Count-only mode** for a quick number of matching DSA ads.
- Fields a source does not disclose are omitted, never left as null or placeholders.

### Output per ad

**DSA library rows (`recordType: "ad"`, `source: "tiktokAdsLibrary"`)**

- `adId`, `adUrl` — TikTok ad ID and its library detail page
- `advertiserName`, `advertiserId`, `advertiserBusinessName`, `advertiserBusinessId`, `advertiserCountry`, `advertiserSponsor`
- `advertiserTikTokUser` — linked TikTok account: `id`, `username`, `displayName`, `followers`, `accountType`, `avatarUrl`, `profileUrl`
- `adTitle`, `adType`, `adFormat`, `showMode`, `adStartDate`, `adEndDate`, `daysActive`
- `adImpressions`, `adImpressionsMin`, `adImpressionsMax`, `avgImpressionsPerDay`
- `adVideoUrl`, `adVideoCover`, `adVideos`, `adImages` — working media URLs
- `ctaText`, `advertisingObjective`, `landingPageUrl`
- `auditStatus`, `auditStatusLabel`, `sorAuditStatus`, `rejectionInfo`, `auditReasons`
- `targetingByLocation`, `adReachByCountry`, `targetingByAge`, `targetingByGender`, `targetAudienceSize`, `targetAudienceSizeMin`, `targetAudienceSizeMax`
- `targetingCountries`, `targetingCities`, `targetingProvinces`, `targetingLanguages`, `targetingDeviceModels`, `targetingOperatingSystems`, `targetingHighSpendingPower`, `audienceTargeting`, `audienceExclude`
- `interestTargeting`, `videoInteractionsTargeting`, `creatorInteractionsTargeting`, `displayMode`
- `searchTotal`, `searchRegion`, `searchQueryType`, `detailsFetched`, `detailUnavailable`
- `source: "tiktokAdsLibrary"`, `recordType: "ad"`, `scrapedAt`

**Creative Center rows (`recordType: "topAd"`, `source: "creativeCenter"`)**

- `adId`, `adUrl`, `adTitle`, `advertiserName`, `adType: "video"`
- `adVideoUrl`, `adVideoCover`, `videoRenditions`, `videoDuration`, `videoWidth`, `videoHeight`
- `ctr`, `likeCount`, `costTier`, `industryKey`, `industryName`, `objectiveKey`, `objectiveName`
- `landingPageUrl`, `commentCount`, `shareCount`, `advertiserCountries`, `isSearchAd`, `ccSource`
- `observedCountry`, `observedPeriod`, `source: "creativeCenter"`, `recordType: "topAd"`, `scrapedAt`

**Count-only runs** emit one row with `recordType: "summary"` and `searchTotal`.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `library` | `library`, `creativeCenter` or `both` |
| `keyword` | string | `""` | Keyword/advertiser text for a DSA search; empty = browse. |
| `advertiserName` | string | – | Exact advertiser name; retried as a keyword if the exact search is empty. |
| `advertiserId` | string | – | Optional business ID to disambiguate an advertiser search. |
| `adIds` | array | `[]` | Direct ad IDs to open. |
| `startUrls` | array | `[]` | TikTok library search or ad-detail URLs. Search URLs contribute their region, keyword/advertiser and date window. |
| `region` | string | `all` | One of 33 country codes or `all`. |
| `startDate` | string | – | Last-shown date from (`YYYY-MM-DD`); default one year ago. |
| `endDate` | string | – | Last-shown date to (`YYYY-MM-DD`); default today. |
| `sortBy` | string | `last_shown_date,desc` | One of six sort orders. |
| `adType` | string | `all` | `all`, `video`, `image`, `text`. |
| `adStatus` | string | `active` | `all`, `active`, `inactive`. |
| `age` | array | `[]` | Any of `13-17`, `18-24`, `25-34`, `35-44`, `45-54`, `55+`. |
| `gender` | string | `all` | `all`, `female`, `male`. |
| `uniqueReach` | string | `all` | `all`, `under10k`, `10k-100k`, `over100k`. |
| `exactPhrase` | boolean | `false` | Treat the keyword as an exact phrase. |
| `includeDetails` | boolean | `true` | Enrich DSA ads from their detail pages. |
| `countOnly` | boolean | `false` | Return one summary row with the matching total. |
| `maxItems` | integer | `50` | Records per source (1–5,000). |
| `ccCountry` | string | `US` | Creative Center market (28 options). |
| `ccPeriod` | string | `30` | `7`, `30` or `180` days. |
| `ccOrderBy` | string | `for_you` | `for_you`, `ctr` or `like`. |
| `ccObjective` | string | `all` | `all` or one of eight campaign objectives. |
| `ccIndustry` | string | `all` | `all` or one of 258 industries. |
| `ccLanguage` | string | `all` | `all` or one of 16 languages. |
| `ccSweep` | boolean | `true` | Sweep filter combinations to collect more than 20 unique top ads. |
| `ccIncludeDetails` | boolean | `true` | Add landing pages, comments and shares. |

#### Example: keyword search in Germany with details

```json
{
  "mode": "library",
  "keyword": "Nike",
  "region": "DE",
  "includeDetails": true,
  "maxItems": 25
}
```

#### Example: exact advertiser, all markets, image ads

```json
{
  "mode": "library",
  "advertiserName": "NIKE Retail B.V.",
  "region": "all",
  "adType": "image",
  "includeDetails": true,
  "maxItems": 100
}
```

#### Example: Creative Center top ads in the US

```json
{
  "mode": "creativeCenter",
  "ccCountry": "US",
  "ccPeriod": "180",
  "ccOrderBy": "ctr",
  "ccSweep": true,
  "maxItems": 100
}
```

#### Example: both sources

```json
{
  "mode": "both",
  "keyword": "skincare",
  "region": "FR",
  "ccCountry": "FR",
  "maxItems": 50
}
```

### Use cases

- **Competitive intelligence** — see every ad a brand runs in Europe, with dates, reach and targeting.
- **Creative research** — collect working video/image creatives and CTAs across markets.
- **Compliance monitoring** — pull audit status, rejection details and advertiser identity.
- **Market sizing** — compare unique-user bands and per-country reach for a category.
- **Global trend spotting** — use Creative Center to find high-performing ads outside the EU.
- **Advertiser due diligence** — check the registered business, sponsor and linked TikTok account.

### FAQ

**Do I need a TikTok account or cookies?**
No. Both sources are public. The actor opens TikTok's public pages once to establish an anonymous session; no login, cookie file or API key is involved.

**How many DSA ads can one search return?**
TikTok serves 12 ads per page and caps a single search at roughly 5,000 results. Split by country, date range or keyword to go deeper. The actor warns when it reaches the cap.

**Why are some ads missing details?**
TikTok marks some ads as unavailable or shows no detail data. Those rows keep their listing data and carry `detailUnavailable: true`. Detail pages are opened for at most 500 DSA ads and 200 Creative Center ads per run; rows beyond those limits keep their listing data.

**Why are my video URLs sometimes expired?**
TikTok's media URLs are signed and time-limited. The actor converts the library's wrapper URLs into working CDN URLs; download or re-host the files promptly if you need them long-term.

**What is the difference between the DSA library and Creative Center?**
The DSA library is the EU transparency database: dates, reach, targeting and advertiser identity. Creative Center is a global showcase of high-performing ads with CTR/likes/video renditions, but no dates or targeting.

**Why does Creative Center return only 20 ads?**
Anonymous visitors get one page of 20 per filter combination. With `ccSweep` on, the actor sweeps periods, rankings, objectives and formats, deduplicates, and collects many more unique ads.

**Can I search Creative Center by keyword?**
Not reliably without a TikTok login. The actor does not offer a Creative Center keyword field; it sweeps the public Top Ads surface instead.

**How do exact advertiser searches work?**
TikTok matches the exact advertiser name (for example `NIKE Retail B.V.`). If that returns nothing, the actor retries the name as a keyword so you still get useful results.

**Why do some fields stay empty?**
TikTok does not disclose them for every ad — for example spend, exact impressions, cities or device targeting. Empty fields are omitted rather than filled with placeholders.

**Is this affiliated with TikTok?**
No. This is an independent third-party actor that reads TikTok's public ad transparency library and Creative Center pages.

# Actor input Schema

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

`library` = TikTok DSA Commercial Content Library (EU/EEA/UK/CH/TR). `creativeCenter` = global Top Ads inspiration feed. `both` = run both and label every row with `source`.

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

Search ads by keyword or advertiser name. Leave empty to browse recent ads in the selected region. (mode=library)

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

Exact advertiser name as shown in the library, e.g. `NIKE Retail B.V.`. If the exact search finds nothing, the actor retries it as a keyword. (mode=library)

## `advertiserId` (type: `string`):

Optional TikTok business ID (`adv_biz_ids`) to disambiguate an advertiser search. Use it with the exact advertiser name. (mode=library)

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

Direct list of TikTok ad IDs. Skips search and opens each ad's detail page. (mode=library)

## `startUrls` (type: `array`):

Paste TikTok library search or ad-detail URLs. Search URLs carry their own region, keyword/advertiser, dates and filters; detail URLs are read as ad IDs. (mode=library)

## `region` (type: `string`):

TikTok DSA library covers EU/EEA countries plus the UK, Switzerland and Turkey. `all` searches the union (capped by TikTok), so split regions for deeper runs. (mode=library)

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

Earliest last-shown date (`YYYY-MM-DD`). Default: one year ago. (mode=library)

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

Latest last-shown date (`YYYY-MM-DD`). Default: today. (mode=library)

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

Result order. (mode=library)

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

Filter by creative type. (mode=library)

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

Active ads are still being shown; inactive ads have stopped. (mode=library)

## `age` (type: `array`):

Only ads targeted at any of these age groups: `13-17`, `18-24`, `25-34`, `35-44`, `45-54`, `55+`. Leave empty for all ages. (mode=library)

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

Only ads targeted at this gender. (mode=library)

## `uniqueReach` (type: `string`):

Filter by TikTok's unique-users-seen band. (mode=library)

## `exactPhrase` (type: `boolean`):

Treat the keyword as an exact phrase instead of individual words. (mode=library)

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

Open each ad's detail page for caption, CTA, landing page, advertiser identity and age/gender reach breakdown. Slower; recommended for smaller runs. (mode=library)

## `countOnly` (type: `boolean`):

Return one summary row with the number of matching ads instead of collecting ads. (mode=library)

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

Maximum records to collect per source (1–5,000). TikTok caps a single library search at about 5,000 results.

## `ccCountry` (type: `string`):

Creative Center market. (mode=creativeCenter or both)

## `ccPeriod` (type: `string`):

Performance window for Creative Center. (mode=creativeCenter or both)

## `ccOrderBy` (type: `string`):

How Creative Center ranks ads. (mode=creativeCenter or both)

## `ccObjective` (type: `string`):

Campaign objective filter. (mode=creativeCenter or both)

## `ccIndustry` (type: `string`):

Creative Center industry filter. 258 industries are available; leave `all` to sweep without an industry. (mode=creativeCenter or both)

## `ccLanguage` (type: `string`):

Ad language filter. (mode=creativeCenter or both)

## `ccSweep` (type: `boolean`):

Anonymous visitors see only 20 ads per filter combination. Sweeping periods, rankings, objectives and formats collects many more unique ads. (mode=creativeCenter or both)

## `ccIncludeDetails` (type: `boolean`):

Fetch each ad's landing page, comment and share counts. (mode=creativeCenter or both)

## Actor input object example

```json
{
  "mode": "library",
  "keyword": "Nike",
  "adIds": [],
  "startUrls": [],
  "region": "DE",
  "sortBy": "last_shown_date,desc",
  "adType": "all",
  "adStatus": "active",
  "age": [],
  "gender": "all",
  "uniqueReach": "all",
  "exactPhrase": false,
  "includeDetails": true,
  "countOnly": false,
  "maxItems": 3,
  "ccCountry": "US",
  "ccPeriod": "30",
  "ccOrderBy": "for_you",
  "ccObjective": "all",
  "ccIndustry": "all",
  "ccLanguage": "all",
  "ccSweep": true,
  "ccIncludeDetails": true
}
```

# Actor output Schema

## `ads` (type: `string`):

Dataset containing all scraped TikTok DSA ads and Creative Center top ads.

# 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",
    "keyword": "Nike",
    "adIds": [],
    "startUrls": [],
    "region": "DE",
    "sortBy": "last_shown_date,desc",
    "adType": "all",
    "adStatus": "active",
    "age": [],
    "gender": "all",
    "uniqueReach": "all",
    "exactPhrase": false,
    "includeDetails": false,
    "countOnly": false,
    "maxItems": 3,
    "ccCountry": "US",
    "ccPeriod": "30",
    "ccOrderBy": "for_you",
    "ccObjective": "all",
    "ccIndustry": "all",
    "ccLanguage": "all",
    "ccSweep": false,
    "ccIncludeDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/tiktok-dsa-ads-transparency-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 = {
    "mode": "library",
    "keyword": "Nike",
    "adIds": [],
    "startUrls": [],
    "region": "DE",
    "sortBy": "last_shown_date,desc",
    "adType": "all",
    "adStatus": "active",
    "age": [],
    "gender": "all",
    "uniqueReach": "all",
    "exactPhrase": False,
    "includeDetails": False,
    "countOnly": False,
    "maxItems": 3,
    "ccCountry": "US",
    "ccPeriod": "30",
    "ccOrderBy": "for_you",
    "ccObjective": "all",
    "ccIndustry": "all",
    "ccLanguage": "all",
    "ccSweep": False,
    "ccIncludeDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/tiktok-dsa-ads-transparency-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 '{
  "mode": "library",
  "keyword": "Nike",
  "adIds": [],
  "startUrls": [],
  "region": "DE",
  "sortBy": "last_shown_date,desc",
  "adType": "all",
  "adStatus": "active",
  "age": [],
  "gender": "all",
  "uniqueReach": "all",
  "exactPhrase": false,
  "includeDetails": false,
  "countOnly": false,
  "maxItems": 3,
  "ccCountry": "US",
  "ccPeriod": "30",
  "ccOrderBy": "for_you",
  "ccObjective": "all",
  "ccIndustry": "all",
  "ccLanguage": "all",
  "ccSweep": false,
  "ccIncludeDetails": false
}' |
apify call vexaloom-labs/tiktok-dsa-ads-transparency-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/tiktok-dsa-ads-transparency-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/rwSaNbXr5duaqxZWs/builds/VN98RbYxVmnD8fOwy/openapi.json
