# Changelog of TikTok Ad Library Scraper — Ads, Creatives & Advertisers (`jaybird/tiktok-ad-library-scraper`) Actor

- **URL**: https://apify.com/jaybird/tiktok-ad-library-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/jaybird/tiktok-ad-library-scraper.md

## Changelog

This project loosely follows [Keep a Changelog](https://keepachangelog.com/). Versions are defined over the output contract (dataset fields and event names).

### \[0.1] — 2026-07-22

#### Fixed — 2026-09-23 (maintenance, not yet released)

- Searches failed with HTTP 421 "system busy" on every attempt because TikTok now requires each client IP to call `/api/v1/location` (as the web app does on page load) before search. Each proxy session now makes that call once, and repeats it after a 421. Verified from one residential IP: with the call, 4/4 searches succeeded; without it, 1/8 (that one right after another location call from the same IP).
- A first page that reports a positive total but contains no ads (seen about once in 17 live searches) is now retried instead of ending the query as "no ads found".
- `OUTPUT` summaries include `failureReason` for blocked queries.

#### Fixed — 2026-07-28

- Runs now stop themselves ~20 s before the Actor timeout, write `OUTPUT`, and exit successfully with whatever they scraped. Previously a run that hit the timeout was killed mid-scrape: its summary was never written and the whole run was reported as failed even though usable ads had been stored. TikTok's per-IP throttling makes throughput too variable to rely on finishing the requested work in a fixed window.
- Detail (enrichment) fetches retry 4 times instead of 8. A throttled detail call could previously stall a run for over a minute for one ad's targeting fields; the card-level row is stored either way and the shortfall is counted in `enrichmentFailures`.
- Prefilled "Max ads per search" is now 20, so the Console's one-click run and Apify's automated test finish well inside the default 5-minute timeout. The default for API callers who omit the field is unchanged at 100.

#### Added — 2026-07-28

- `OUTPUT` reports `stoppedAtRunTimeout`, `queriesNotStarted`, `requestRetries`, and `proxySessionRotations`, so a slow or partial run is diagnosable after the fact. Proxy escalation is now logged at warning level rather than debug.

#### Added

- Initial release. Scrapes TikTok's Commercial Content Library (`library.tiktok.com`) via its public JSON API — no login, headless browser, or request signing.
- Advertiser and keyword search modes. Advertiser searches are filtered to the advertiser's own ads to cut TikTok's loose fuzzy matches.
- Optional per-ad enrichment (`includeTargeting`, default on): call to action, advertising objective, advertiser business ID and registry country, audience-size estimate, impressions by country, and full targeting (countries, age bands, gender, languages, OS).
- Country and date-range filters; `maxResultsPerQuery` cap.
- Pay-per-event billing: one `ad-scraped` event per unique ad ($2.50 / 1,000 at the FREE tier), deduped across searches. `apify-actor-start` billed automatically by Apify.
- Datacenter → residential proxy escalation with token refresh and backoff on TikTok's "system busy" (HTTP 421) rate limit.
- Per-search summaries and aggregate run health written to the `OUTPUT` key-value record.

#### Known limitations

- Covers EU/EEA-served ads only (the scope of TikTok's Commercial Content Library).
- Ad creatives are served from short-lived signed CDN URLs that expire.
- Creative Center "Top Ads" (global, performance-ranked) is not yet included — planned as a separate mode.
