TikTok Ads Scraper - Ad Library at $0.45/1K
Pricing
from $0.45 / 1,000 ad scrapeds
TikTok Ads Scraper - Ad Library at $0.45/1K
Reads TikTok's public Commercial Content Library by keyword, advertiser, country and date. One row per ad: advertiser, caption, first and last shown dates, countries targeted, unique-users band, video, thumbnail, CTA and landing URL. EEA and UK only - no US edition.
Pricing
from $0.45 / 1,000 ad scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
TikTok Ads Scraper — Commercial Content Library
TikTok publishes an ad archive at library.tiktok.com/ads because EU law makes it. This reads that
archive by keyword, advertiser, country and date, and gives you one flat row per ad.
Each row has the advertiser, the ad caption, the first and last dates it ran, every country it was shown in, the unique-users band TikTok publishes for it, the video and thumbnail, the call-to-action button text and the landing page the ad clicks through to.
Read the coverage note before you plan anything around this. The archive only exists because of EU and UK transparency rules, so it only covers the EEA plus the UK, Switzerland, Norway, Iceland and Liechtenstein. There is no US edition. Nothing before 2022-10-01 is in it either.
No account and no browser. The library hands a guest token to anyone who asks for one, and that's what the run uses.
Price
$0.45 per 1,000 ads, plus a $0.0015 start fee per run.
| Ads | Total |
|---|---|
| 100 | $0.0465 |
| 1,000 | $0.4515 |
| 10,000 | $4.5015 |
One ad-scraped event per ad row. Nothing else is metered per row. The sample row and every
diagnostic row are free and carry "charged": false. Ads already seen earlier in the same run are
dropped before they're charged, so a creative matching two of your search terms costs you once. A
country code or date the library doesn't support comes back as a free diagnostic row rather than a
billed one.
Input
{"searchTerms": ["running shoes", "protein powder"],"countries": ["DE", "FR", "IT"],"dateFrom": "2026-07-01","dateTo": "2026-08-15","maxItems": 100,"includeAdDetails": true}
| Field | What it does |
|---|---|
searchTerms | Matches advertiser names and ad captions. Up to 20 per run; the row budget is split evenly between them. |
advertiserNames | Registered advertiser names, e.g. NIKE Retail B.V.. Each is resolved against the library's own advertiser register first, then that entity's ads are pulled. A brand word like Nike picks up every registered entity whose name starts with it. |
adLibraryUrls | Paste addresses straight from library.tiktok.com/ads. The country, date range, advertiser, sort order and format filters already in the URL get read back out and used. |
countries | Two-letter codes, or all. Only these exist: 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. On its own, with no search terms, it means "every ad running in these countries". |
dateFrom / dateTo | YYYY-MM-DD. Defaults to the last 30 days. An earlier date than 2022-10-01 is moved forward to it. |
maxItems | Total rows across every target. Default 20, ceiling 20,000. |
includeAdDetails | On by default. This fetches the per-ad transparency record, and it's the only source of landingUrl, callToAction, advertisingObjective, advertiserRegistryCountry, countriesTargeted, targetAudienceSize and impressionsByCountry. Turn it off for a lighter run with those fields null. |
adFormat | all, video, image or text. |
adStatus | all, active (still running) or inactive (stopped). |
sortBy | create_time,desc (default), last_shown_date,desc, impression,desc and the ascending versions. |
proxyUrls | Leave empty unless you already pay for proxy servers and want traffic to leave through them. |
sessionCookies | Leave empty. Nothing is logged in and the archive doesn't need it. The field is a safety net: if TikTok ever stops serving anonymous callers, your own sessionid here gets the run a rate limit nobody else shares. |
Empty input gives you one labelled sample row, free, so you can see the shape first.
Output
{"ok": true,"charged": true,"recordType": "ad","searchTerm": "running shoes","adId": "1873543311265906","advertiserName": "B - SPORTING LIMITED","caption": "Shop our range of running shoes & clothing from all the top brands at the best prices","firstShownDate": "2026-08-15T00:00:00.000Z","lastShownDate": "2026-08-15T00:00:00.000Z","countriesTargeted": ["GB"],"uniqueUsersSeen": "0-1K","videoUrl": "https://library.tiktok.com/api/v1/cdn/1786906839/video/...","thumbnailUrl": "https://p16-common-sign.tiktokcdn.com/tos-alisg-p-0051c001-sg/...","landingUrl": "https://www.sportsshoes.com/?utm_source=tiktok&utm_medium=cpc&...","callToAction": null,"adFormat": "video","adDetailUrl": "https://library.tiktok.com/ads/detail/?ad_id=1873543311265906","advertiserId": "6877843515099841282","advertiserRegistryCountry": "United Kingdom","paidBy": "B - SPORTING LIMITED","advertisingObjective": null,"adStatus": "active","imageUrls": ["https://p16-common-sign.tiktokcdn.com/tos-alisg-p-0051c001-sg/..."],"targetAudienceSize": "24.5M-30.0M","impressionsByCountry": { "GB": "0-1K" },"targetedAgeGroups": ["18-24", "25-34", "35-44", "45-54", "55+"],"targetedGenders": ["female", "male", "unknown"],"searchedRegions": ["all"],"rejectionReason": null,"scrapedAt": "2026-08-16T19:00:39.536Z"}
Things worth knowing about specific fields:
uniqueUsersSeenandimpressionsByCountryare bands, not numbers —0-1K,100K-1M. That's how TikTok publishes them. There is no exact impression count anywhere in the archive.advertiserRegistryCountryis where the paying entity is registered, which is often not where the ad ran. Chinese and US entities buying ads in Germany, France and Spain are common in the archive.callToActionandadvertisingObjectiveare null in the row above because that advertiser didn't set them. Plenty of ads carry them (Shop now/Sales,View TikTok profile/Community interaction). Null means the archive has no value, not that the fetch failed.videoUrlpoints at TikTok's own CDN through a signed path. Download it during or soon after the run rather than months later.firstShownDateandlastShownDateare day-granular. TikTok doesn't publish a time.
Limits
- Coverage is EEA + GB, CH, NO, IS, LI. There is no US edition of this library.
region=USis answered with an error by TikTok itself. If you need US ad data this is the wrong tool. - Nothing before 2022-10-01 exists in the archive.
- TikTok throttles this API hard, and the throttle is aggressive on cloud addresses. When a search
gets throttled to the point of no results you get an uncharged
RATE_LIMITEDdiagnostic row and a succeeded run, not a failure and not a bill. Retrying later is usually the fix; narrower searches and lowermaxItemshelp. - Pages come back 12 rows at a time whatever the run asks for. That's server-side, not a setting.
- Sorting by
last_shown_datemakes TikTok's own library repeat some ads across pages and skip others.create_time,descdoes not, so that is the default. Ad ids are de-duplicated across the whole run either way. - No exact impression counts, no spend, no ad performance. The archive publishes bands and dates, and nothing here invents the rest.
- Turn
includeAdDetailsoff and the landing URL, CTA, objective, targeting and audience-size fields all come back null. Those live only on the per-ad record. - Hard ceilings: 20 search terms, 20 advertiser names, 20 URLs, 20,000 rows per run.
Questions
Can I get US TikTok ads? No. The library is an EU/UK transparency archive and TikTok doesn't publish a US edition of it.
Do I need a TikTok account? No. The run mints its own guest token from a public endpoint. The
sessionCookies field exists only as a fallback if that ever stops working.
What does a RATE_LIMITED row mean? TikTok answered "system busy" to every attempt for that
search. You aren't charged for it. Try again later or narrow the search.
Can I get the ad creative file? You get videoUrl, thumbnailUrl and imageUrls. Fetching and
storing the media itself is on you.
Can I schedule it? Yes. Nothing is held between runs. adId is stable, so diff on it.