TikTok Ads Library & Top Ads Scraper — Targeting, Advertisers avatar

TikTok Ads Library & Top Ads Scraper — Targeting, Advertisers

Pricing

from $0.50 / 1,000 ad library ads

Go to Apify Store
TikTok Ads Library & Top Ads Scraper — Targeting, Advertisers

TikTok Ads Library & Top Ads Scraper — Targeting, Advertisers

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.

Pricing

from $0.50 / 1,000 ad library ads

Rating

0.0

(0)

Developer

Berkan Kaplan

Berkan Kaplan

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 hours ago

Last modified

Categories

Share

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)

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")

GroupFields
AdadId, 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 manyfirstShown, lastShown, daysShown, uniqueUsersSeen (TikTok's range, e.g. 1M-10M), uniqueUsersSeenMin, uniqueUsersSeenMax
Reach by countryreachByCountry[]: country, uniqueUsers, uniqueUsersMin, uniqueUsersMax, byAgeAndGender[] (age, gender, uniqueUsers)
TargetingtargetCountries, 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)
AdvertiseradvertiserName, advertiserBusinessId, paidBy (the "Ad paid for by" entity, often the media agency), advertiserCountry (registered location), advertiserTikTokUsername, advertiserTikTokFollowers (+ Text), advertiserTikTokUrl
Searchquery, 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:

{
"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):

{
"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

InputWhat it doesDefault
modelibrary (Ad Library) or topAds (Creative Center Top Ads)library
searchTermsKeywords, 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—
searchBykeyword or advertiser (the name is matched to TikTok's advertiser list; the match and other candidates are in the SOURCE_REPORT)keyword
countriesall 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, TRall
datePreset, dateFrom, dateToLast 7 / 30 / 90 / 180 / 365 days, or custom dateslast 30 days
adStatusall, active, inactive (TikTok's own site shows only active ads by default)all
adFormatall, video, image, textall
sortByLast 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 orderlast shown, newest first
maxAdsPerQueryAds per search term, up to 5,000. The form starts at 10100
includeDetailsTargeting, reach by country/age/gender, payer, registered country, TikTok account, landing page, CTA, objectiveon
outputads, advertisers (one row each), or bothads
topAdsCountries, topAdsPeriod, topAdsSortByTop Ads country list (28), last 7 / 30 / 180 days, rankingUS, 30 days, For you
topAdsObjectives, topAdsIndustries, topAdsLanguagesFilters (empty = all)—
maxTopAdsTop Ads per country. The form starts at 10100
sweepFiltersCollect beyond TikTok's 20 ads per filter combinationon
includeTopAdDetails, includeTopAdAnalyticsLanding page, comments, shares, countries · retention and CTR curveson · off
onlyNewAds, monitorNameDeliver only ads earlier runs (same monitor name) did not deliveroff
proxyConfigurationNot 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 Librarynone

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)

{ "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)

{ "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

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

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

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

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

{ "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:

InputRowsTimePeak memory
Form default (nike, 10 ads with details)10 ads24 s289 MB
One advertiser, 1,000 ads with details (NIKE Retail, 90 days)1,000 ads (997 with details)19 min310 MB
Two keywords, 150 ads each with details ("CRM", "temu")300 ads + 98 advertiser rows7.7 min456 MB
Biggest advertisers in Germany (300 ads, no details)222 advertiser rows3.7 min279 MB
Keyword temu, 1,000 ads without details1,000 ads5.2 min227 MB
Keyword temu, maximum 5,000, without details4,440 ads (the end of TikTok's list)27 min239 MB
Top Ads, 5 countries × 100, with details380 ads3 min176 MB
Top Ads, US, with retention and CTR curves124 ads1.5 min179 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

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();
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:

FieldOne big brand, 1,000 ads (NIKE Retail, 90 days)300 keyword ads, many small advertisers ("CRM", "temu")
Advertiser name, first/last shown, unique users100%99-100%
Business ID, who paid, registered country99.7%98-100%
Reach by country · targeting (countries, ages, genders, audience size)99.7%99-100%
Reach by age and gender86%79%
Landing URL66%51%
Call to action · objective86% · 86%46% · 79%
Video or image54% (catalog ads have none)100%
TikTok account of the advertiser90%15%
Interests20%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:

EventWhen
adeach Ad Library ad row
ad-detailsthe ad row also carries its detail page (targeting, reach by country, payer…)
advertisereach advertiser row
top-adeach Top Ads row (detail included)
top-ad-analyticsthe 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).

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.