TikTok Ads Library Scraper | Export & Changes avatar

TikTok Ads Library Scraper | Export & Changes

Pricing

from $0.36 / 1,000 results

Go to Apify Store
TikTok Ads Library Scraper | Export & Changes

TikTok Ads Library Scraper | Export & Changes

Export TikTok Commercial Content Library ads by keyword or advertiser, with available media, reach and targeting. Compare full exports with disappearance safeguards.

Pricing

from $0.36 / 1,000 results

Rating

0.0

(0)

Developer

Eli J

Eli J

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

What you can export

Use this TikTok Ad Library scraper for commercial-ad research and recurring creative tracking. Search the Commercial Content Library by keyword or exact advertiser to export available shown dates, media, reach, impressions and targeting.

Compare a full prior export for new, changed and observed-absent ads. An ended row describes disappearance from a complete query read; it does not independently confirm that a campaign stopped.

Try the example input

{
"advertisers": [],
"searchTerms": [
"SHEIN"
],
"regions": [
"NL",
"DE"
],
"maxItems": 10
}

For an advertiser, use its exact name from the Library's advertiser suggestions. An optional business ID must match that name; a business ID by itself cannot resolve a name. With details enabled, the advertiser in each ad's detail supplies the identity. With details off, each card must match the selected name; a supplied business ID forces details because cards cannot verify it.

{
"advertisers": [{"name": "NIKE Retail B.V.", "businessId": "6876453864464188162"}],
"regions": ["NL"],
"startDate": "2026-09-06",
"endDate": "2026-10-06",
"maxItems": 200
}

Input

FieldTypeWhat it does
advertisersarrayObjects with required name and optional numeric-string businessId. Nonblank names match exact suggestions, case insensitive; ambiguous names and mismatched IDs go to ERRORS. [{"name":""}] explicitly browses the source's advertiser mode (query_type=2); a blank name cannot carry an ID. Empty/omitted/null arrays request no advertiser queries.
searchTermsarrayKeyword strings across advertisers. [""] explicitly browses the source's keyword mode (query_type=1). Empty/omitted/null arrays request no keyword queries.
regionsarraySearch regions: 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, TR. Include all to select all 33 regions, case insensitive; duplicates are removed. Each is a separate query. Empty/omitted/null selects no advertiser or keyword queries.
adUrlsarrayFull Library /ads search URLs with one supported region, or /ads/detail/?ad_id=ID URLs. Search URLs retain their query, second-resolution date boundaries and ad type. Each date omitted by a search URL inherits its startDate/endDate input; a URL-supplied date wins. Direct detail URLs select one ad independently of regions and date inputs. Empty/omitted/null requests no URL queries.
adTypestringALL, VIDEO, IMAGE or TEXT; omitted/null uses ALL. Search URLs can override it with ad_type; direct detail URLs ignore it.
startDatestringInclusive UTC YYYY-MM-DD boundary; omitted/null is 30 days before the end date.
endDatestringInclusive UTC YYYY-MM-DD boundary; omitted/null is today's UTC date.
maxItemsintegerMaximum distinct ads scanned per query and region, including unchanged ads. Omitted/null uses 100; 0 requests no work.
fetchDetailsbooleanOmitted/null uses true. false exports list-card fields without per-ad detail calls. A supplied advertiser businessId forces details for that request; direct URLs always use their detail endpoint.
baselineDatasetIdstringOptional read-only dataset picker. Select a full export from this Actor with the same queries, regions, date inputs and effective basic/detail mode to switch to monitor mode.

Omitted work inputs never fill themselves with sample queries. {} finishes successfully with guidance and no rows. Invalid supplied input is recorded in ERRORS with guidance before any request. Use fixed date boundaries to track membership over time: an omitted date follows the current 30-day window, and ads can leave that window while remaining available elsewhere in the Library.

For a direct ad, copy its Library detail URL:

{"adUrls": ["https://library.tiktok.com/ads/detail/?ad_id=101"], "maxItems": 1}

For a Library search URL, use https://library.tiktok.com/ads/?region=NL&adv_name=SHEIN&query_type=1&ad_type=1. Only the active-ad/default audience filters and the default create_time,desc sort are supported; non-default or unknown search filters are refused into ERRORS. Advertiser URLs use query_type=2 and an exact adv_name, optionally adv_biz_ids. A supplied business ID disambiguates exact-name suggestions and every detail must match the selected advertiser.

A search URL with no adv_name, such as https://library.tiktok.com/ads/?region=NL, browses the source's keyword mode for the selected region/date/type filters. Add query_type=2 for blank advertiser-mode browsing. The source returns different result sets for these two modes; the Actor preserves the requested mode.

For a faster browse export:

{"advertisers":[{"name":""}],"regions":["FR"],"startDate":"2025-01-01","maxItems":20,"fetchDetails":false}

Output

JSON, CSV, Excel and API export are available through the run's dataset. The following illustrative row shows the shape; optional values can be null or empty.

With fetchDetails:false, rows carry list-card identity/name, shown dates and source timestamps, audience bucket/bounds, creative media/type, caption, audit/rejection information and category when supplied. advertiserBusinessId and detail-only fields (impressions, targeting, payer/profile, landing page, CTA/objective and download URL) are null or empty. regions is empty because cards do not supply an impression-region breakdown; the requested region remains in sourceUrl. Card impression:0 is not interpreted as a measured impression count. Keyword and browse rows use the card's advertiser label; named requests verify that label exactly, case insensitive.

{
"adId": "101",
"advertiserName": "Example Advertiser",
"advertiserBusinessId": "9001",
"firstShown": "2026-09-07",
"lastShown": "2026-10-05",
"firstShownTimestamp": 1788739200000,
"lastShownTimestamp": 1791158400000,
"regions": ["NL"],
"reachRange": "1K-10K",
"reachMin": 1000,
"reachMax": 10000,
"impressionRange": "10K-100K",
"impressionMin": 10000,
"impressionMax": 100000,
"targetAudienceMin": null,
"targetAudienceMax": null,
"regionImpressions": [{"region": "NL", "impressionRange": "10K-100K", "impressionMin": 10000, "impressionMax": 100000}],
"targeting": {"countries": ["NL"], "audience": "No"},
"creativeType": "video",
"videoUrls": ["https://cdn.example/ad.mp4"],
"imageUrls": ["https://cdn.example/cover.jpg"],
"adText": "Example ad caption",
"landingPage": null,
"paidForBy": "Example payer",
"advertiserCountry": null,
"advertiserProfile": null,
"callToAction": null,
"audienceBreakdown": [],
"advertisingObjective": null,
"auditStatus": "1",
"rejectionInfo": null,
"adSubject": null,
"downloadUrl": null,
"daysRunning": 29,
"sourceUrl": "https://library.tiktok.com/ads/detail/?ad_id=101&region=NL&adv_name=SHEIN&query_type=1&adv_biz_ids=&start_time=1788652800000&end_time=1791331199000",
"scrapedAt": "2026-10-06T17:00:00Z"
}
Output fieldMeaning
adIdLibrary ad identity, a string.
advertiserName, advertiserBusinessIdAdvertiser from the matching ad detail. List-only rows use the card name and a null business ID. Neither payer nor a brand in a caption is substituted.
firstShown, lastShownSource millisecond timestamps converted to UTC dates; null if absent.
firstShownTimestamp, lastShownTimestampOriginal source Unix timestamps in milliseconds, without rounding; null if absent.
regionsRegions in the ad's detail impression breakdown, which may include regions beyond the requested search region.
reachRangeSource audience bucket, retained as text; never an exact count.
reachMin, reachMaxInteger lower/upper counts parsed from reachRange, not exact delivered reach.
impressionRange, regionImpressionsTotal and region-level impression buckets, retained as text; absent buckets are null.
impressionMin, impressionMaxInteger lower/upper counts parsed from the total impressionRange. Each regionImpressions entry also has its own impressionMin and impressionMax.
targetAudienceMin, targetAudienceMaxInteger lower/upper counts from targeting.target_audience_size; its original text remains in targeting. Target audience size is distinct from observed reach.
targetingSource targeting summary: age/gender, targeted audience size, geography, language, devices, operating systems, interests and interaction/audience selections when shown. Source names and value shapes are retained.
creativeTypevideo or image from the proved Library display modes. Unproved detail modes go to ERRORS and make the query partial.
videoUrls, imageUrlsSource media links; images include video covers. Signed links can expire. Download media promptly.
adText, landingPageSource caption and outbound URL when supplied, otherwise null. Landing pages are often absent.
paidForBy, advertiserCountrySource sponsor/payer and advertiser registration location, otherwise null. Payer can differ from advertiser.
advertiserProfileSource TikTok account object with username, displayName, followers, accountType, profileUrl, avatarUrl; null when absent. Followers retain the source's abbreviated text.
callToAction, advertisingObjectiveSource CTA and objective when supplied, otherwise null.
auditStatus, rejectionInfoRaw source audit code and rejection information, otherwise null. An audit code is not interpreted as proof that a campaign is currently running. Rejection information retains its source JSON shape.
adSubject, downloadUrlSource industry/category and app download URL when supplied, otherwise null.
daysRunningInclusive count of UTC days from first shown to last shown; null if either date is absent. It does not measure continuous delivery or today's activity.
audienceBreakdownSource impression buckets by region, age, gender, impressionRange, with integer impressionMin/impressionMax on every entry; an empty array when absent.
sourceUrlAd detail permalink retaining query/region/date/ad-type context; direct URL reads retain only ad ID. Empty date parameters represent omitted date inputs.
scrapedAtUTC timestamp of this run's query work.
changeStatusMonitor mode only: new, changed or ended.
changedFieldsChanged row field names, present only for changed rows.

Bucket bounds expand K/M/B by 1,000/1,000,000/1,000,000,000. For example, 11.7M-14.2M becomes 11700000–14200000, and 159K has both bounds 159000. Missing, empty, unrecognized, reversed or nonintegral ranges have null bounds and retain any supplied text. These are bucket boundaries, not exact counts.

Monitor ads

  1. Run an export and keep its dataset ID.
  2. Run again with the same query, region, date and effective basic/detail mode inputs, choosing that dataset in baselineDatasetId. A basic/detail mode mismatch is refused to avoid false changes.
  3. Export the change rows. Keep using a full export as the baseline; a change-feed dataset is refused because it omits unchanged ads.

new means absent from the selected baseline, including ads omitted by a previous cap. It is not a claim about campaign launch time. changed compares substantive output fields, excluding ad ID, source URL, observation timestamp and the volatile lastShown, daysRunning and advertiserProfile.followers values. Equivalent ordering or duplicate values in targeting/breakdown arrays, signed-media query parameters, CDN hosts and relay tokens do not create changes. Actual media paths and landing-page URL changes do.

Pure lastShown advances, derived daysRunning extensions and profile follower growth produce no change row or result charge. A delivered row still carries their current values. Other advertiser profile fields remain substantive.

Numeric bounds and source timestamps are snapshot conveniences and do not independently trigger changes; the original bucket text and first-shown date remain compared. Earlier full export baselines are accepted: missing numeric bounds are derived from their retained text, and missing source timestamps remain null rather than inferred from dates.

ended means a baseline ad was not found in this run's complete read of that same query context. It is an observed disappearance, not independent confirmation that a campaign stopped. Complete requires a terminal page, every distinct ad counted against the source's reported total, and no cap, source failure or charge stop. A source that drifts or omits IDs is partial and cannot generate ended rows. Previously observed IDs are retained conservatively across a fresh-session retry.

Coverage and errors

The run's COVERAGE record reports each query as complete or partial, distinct valid ads scanned and the stop reason (end, cap, source-error, rejected-ad, snapshot-drift or charge-limit). Search and detail errors, unresolved advertisers and queries with no ads go to ERRORS, never the dataset. An unavailable or malformed ad detail is recorded with its ad ID; later ads continue, but that query cannot infer ended rows. Partial results remain available. A run with no rows fails only if every attempted query failed; a genuine empty answer succeeds with guidance. Direct detail reads never infer ended ads.

COVERAGE also records effectiveStartTime and effectiveEndTime as the UTC Unix-second boundaries used for a search. They are null for direct details or queries stopped before a search window was attempted, including unresolved advertisers.

The Actor uses anonymous Chrome-impersonated HTTP over Apify datacenter proxies. Search sessions rotate after four pages and separate detail sessions after four reads. A search page or detail HTTP/application non-answer receives up to three attempts on fresh sessions; page retries preserve its offset and cursor. Query-total inconsistency receives up to three full traversals while retaining every discovered ID conservatively. Pagination begins at page zero and deduplicates ad IDs within each query. The same ad can appear once under each selected query/region context. No residential proxy is used.

Coverage limits

Supported surface: public TikTok Commercial Content Library paid ads search and ad details, including advertiser suggestions, in the 33 regions listed above. The Library offers these regions; some return no matches for a given keyword, which does not imply an empty Library. Coverage varies by advertiser, date and region. Creative Center top ads, its CTR/likes/ranking data, other commercial content, reporting surfaces and the official research API are outside this product. No TikTok account is needed.

Video and image filters returned populated search and detail answers in the bounded check. The Library offers a text filter, which returned a genuine empty answer for that check; a populated text detail has not yet been observed.

Some moderated-ad details return rejection information while withholding advertiser identity. Those ads go to ERRORS because a correctly identified row cannot be produced; their query remains partial even when the ad ID appeared in search.

The Library's robots.txt disallows /ads and /api. This Actor reads public business advertising content; use it in accordance with your applicable obligations. Library interfaces and optional field availability can change. This Actor is independent of TikTok.

Billing and support

Pricing is per 1,000 ads. Each delivered export or change row is one billable result; unchanged ads and ERRORS entries are never dataset results. Actor Start may also apply according to the listing's pricing. A binding customer charge limit stops before another ad detail, page or query is read.

For support, open an issue with the run ID, query inputs and the relevant ERRORS or COVERAGE entry. Avoid sharing credentials or private datasets publicly.