TikTok Ads Library Scraper — TikTok Creative Center Top Ads
Pricing
from $0.40 / 1,000 ads
TikTok Ads Library Scraper — TikTok Creative Center Top Ads
Scrape the TikTok Ad Library, TikTok's ads transparency archive: every ad an advertiser runs, with targeting, reach per country, landing page, payer and TikTok account. Plus TikTok Creative Center Top Ads with CTR curves. A TikTok ads scraper and ad spy for competitor ads. No login.
Pricing
from $0.40 / 1,000 ads
Rating
0.0
(0)
Developer
Hyperbach
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Every ad an advertiser runs in TikTok's Ad Library, with its full record — the targeting (ages, genders, interests, audience size, languages, devices), reach per country and the age × gender breakdown, the landing page with its UTMs, the category, the objective, the CTA, who paid, and the advertiser's TikTok account. Pin an advertiser by name and get its own ads, not everyone who mentions it. Search keywords, a creator's branded posts, or paste any library URL, with every filter the library has. Plus the Creative Center's Top Ads — TikTok's best-performing ads worldwide, with the landing page, likes, comments, shares, the per-second CTR and retention curves and the Spotlight picks, in the same row shape. Follow a competitor on a schedule and get only its new ads. Same column names as our Google Ads Transparency Scraper, Meta Ad Library Scraper and LinkedIn Ad Library Scraper. No login, no cookies, proxies handled for you.
Why this scraper, not the other TikTok ad actors
- It reads the library the way TikTok serves it. Of the TikTok ad actors we ran on one advertiser (2026-09-29), several came back with "0 rows, SUCCEEDED": the library refuses a search without its per-connection entry ticket (HTTP 421 "system busy"), refuses page 2 without the previous page's search id (HTTP 425), accepts each detail ticket once, and stops a connection after about 100 detail records. This Actor follows those rules, moves to a fresh connection before the limit, and a run that could not read the source ends PARTIAL or FAILED and says why — never green and empty.
- The advertiser, not everyone who mentions it. A keyword finds every ad that uses the word;
advertiserspins the advertiser itself. Give its name as TikTok registers it and the run takes every business id TikTok lists under exactly that name; giveName | idto pin one. Each row carriesadvertiser_idandadvertiser_name, so the next run can use the pair. - Walked to the end, and said so. TikTok serves about 5,000 ads per query, then repeats its last page; a keyword's total stops at 5,000. The run splits the date window until each part is under the cap, walks each part in both directions (ties on the date reshuffle between pages), and the run summary says, per search, TikTok's own total, how many it listed and whether the walk is complete. On one UK advertiser (2025-10-01 to 2026-09-30) it returned 220 of TikTok's 221 ads, each with its detail record.
- The whole record, not the list card. Each library row carries what the detail record publishes: targeting per country (age groups, genders), interests, video and creator interactions, custom audiences, languages, cities, devices, operating systems, the targeted audience size as numbers, reach per country and the age × gender breakdown where TikTok publishes it, landing page with its UTMs, category, objective, CTA, payer, the registered country, the advertiser's TikTok account with its followers, and — for ads TikTok removed — the removal reason.
- Top Ads in the same rows. The Creative Center's Top Ads for any of its 28 countries and three periods, sorted by TikTok's seven orders, filtered by industry, objective, language, format and likes. Logged out TikTok serves 20 per list;
topAdsSweepreads the list under every sort, objective, likes tier, format, industry and language and deduplicates (more than 100 of TikTok's ~130 for one country and period). The detail adds landing page, countries, comments and shares;topAdsMetricsadds the per-second CTR, conversion, click and retention curves and five percentiles. The CTR is TikTok's rank bucket (ctr_top_percent: 6 = "Top 6%"), not read backwards. - Monitoring with a change feed.
onlyNewAdsskips every ad an earlier run delivered — not returned, not charged — and brings back an ad whose last shown day, reach band, status or likes moved, markedchange_type: changed. Every row carriesfirst_seen_at,last_seen_atandtimes_seen; Top Ads carry theirrankandprevious_rank;includeEndedAdsadds a free row for each ad a complete walk no longer lists. - What the ad is doing, as columns.
tagAdsreturns typed tags — angle, CTA intent, tone, offer type, funnel stage, sentiment — each with its confidence, the same tags our LinkedIn and Meta actors return.analyzeAdswrites the hook, offer, audience and strategy;ocrImageAdsreads the words in image ads;transcribeVideosreturns what the video says and its first three seconds. No API key of yours needed. - Counts, lookups and reports.
resultType: countsreturns TikTok's total per search from one call (a search with no ads is free; ready-made: Check which advertisers run TikTok ads).resultType: advertiserslists every business id TikTok has for a name, with its number of ads.includeAdvertiserReportadds TikTok's own advertiser report: where its ads ran, country by country, and how many it published each month. - Core columns shared with our Google, Meta and LinkedIn ads scrapers.
creative_id,ad_url,advertiser_name,advertiser_id,body_text,destination_url,first_shown,last_shown(YYYY-MM-DD),days_shown,image_urlandad_formatmean the same thing in all four, so a competitor's ads on four platforms stack in one sheet on those columns. The rest differ by platform (reach vs impressions, targeting names, TikTok's own status).
Who it's for
- Performance marketers and media buyers — a competitor's live TikTok ads with the targeting they chose, where they run, how many people they reach, and the landing pages with their UTMs.
- Agencies and creative strategists — the Top Ads in a client's industry with TikTok's own curves and percentiles, the long runners in the library, and typed tags for angle and offer — a creative brief from data.
- Brands and brand-safety teams — every ad paid for in your name, which agency paid, which ads TikTok removed and why, and the creators posting branded content about you.
- Researchers and compliance teams — the EU transparency record TikTok publishes per ad — payer, reach per country, targeting, removals — in columns, over time.
Quick start
Every ad one advertiser runs, with its detail
{"advertisers": ["Samsung Electronics GmbH"],"maxAds": 100}
One advertiser pinned by name and id, in Germany and France, last 90 days
{"advertisers": ["Notion | 7377365644930662401"],"countries": ["DE","FR"],"dateRange": "last-90-days","maxAds": 50}
A keyword across every advertiser, list fields only (cheap)
{"keywords": ["skincare"],"includeDetails": false,"maxAds": 200}
Top Ads in the US for the last 30 days, with curves
{"topAdsCountries": ["US"],"topAdsPeriod": "30","topAdsSortBy": "ctr","topAdsMetrics": true,"maxAds": 20}
Which of these advertisers run ads, and how many
{"advertisers": ["Samsung Electronics GmbH","Notion"],"resultType": "counts"}
Monitoring — only what appeared or changed since the last run
{"advertisers": ["Samsung Electronics GmbH"],"onlyNewAds": true}
Output
One record per ad:
| field | meaning |
|---|---|
row_type | ad for an ad; commercial_content for a creator's branded post (creators); count for a resultType: counts row; advertiser_match for a resultType: advertisers row; advertiser for an advertiser report (includeAdvertiserReport); advertiser_profile, landing_page and hashtag for the free summaryRows; ended for an ad a complete walk no longer lists (includeEndedAds); not_found for an id TikTok no longer has. |
surface | library — TikTok's Ad Library (ads shown in the EU, EEA, Switzerland and the UK, with the transparency record); top_ads — the Creative Center's Top Ads (TikTok's best-performing ads, worldwide). |
creative_id | TikTok's ad id: the library ad id (16 digits) or the Top Ads id (19 digits). Unique per ad; the key for onlyNewAds. |
ad_url | The ad's page: the library's detail page or the Creative Center's Top Ads page. |
ad_format | video or image (an image ad can hold several images). |
creative_available | Whether TikTok shows the creative. An active ad can have its video and images withheld; removed ads have none. |
advertiser_name | The advertiser as TikTok registers it (library), or the brand name on a Top Ad (often empty there). |
advertiser_id | TikTok's business id of the advertiser (library ads). With advertiser_name it pins the advertiser in advertisers (`Name |
advertiser_location | The country the advertiser is registered in, as the library states it. |
payer | Who paid for the ad (the library's "Paid for by"), often an agency. |
advertiser_tiktok_username | The advertiser's TikTok account, when the ad is linked to one. |
advertiser_tiktok_name | That account's display name. |
advertiser_tiktok_url | That account's profile. |
advertiser_tiktok_followers | That account's followers, as a number (the library shows "276.7K"). |
advertiser_tiktok_avatar_url | That account's avatar. |
advertiser_tiktok_account_type | The account type TikTok reports (BLUEV_BA = a verified business account). |
creator_username | creators rows: the creator who posted the branded content. |
creator_url | creators rows: the creator's profile. |
content_label | creators rows: TikTok's commercial-content label code (1 or 2), as the library gives it. |
body_text | The ad's caption (library: the ad text; Top Ads: the title). |
hook_text | The caption's first sentence or line — what the viewer reads first. |
hashtags | The caption's hashtags, lower-cased, without #. |
mentions | The accounts the caption mentions, without @. |
cta | The call-to-action button as the ad words it ("Shop now"). Library detail only. |
cta_type | The CTA as one value across languages: shop, buy, learn_more, download, install, sign_up, book, contact, … other. |
objective | The campaign objective: the library's advertising objective ("Reach") or the Top Ad's objective ("Conversions"). |
objectives | Top Ads: every objective TikTok lists for the ad. |
category | The library's ad category ("Tech & Electronics", "News & Entertainment"). |
industry | Top Ads: the industry, by TikTok's own name. |
industry_id | Top Ads: TikTok's industry id (topAdsIndustries takes it). |
destination_url | Where the ad sends the click, with the advertiser's UTM parameters kept. |
landing_domain | The destination's domain. |
image_url | An image ad's first image, or a video ad's cover. |
image_urls | An image ad's images (signed links that expire at media_expires_at). |
cover_url | A video ad's cover frame. |
video_url | The video (library: TikTok's link, which redirects to the CDN; Top Ads: the best rendition). |
video_urls | Top Ads: every rendition, best first: quality ("1080p"), height, url. |
video_id | Top Ads: TikTok's id of the video file. |
video_duration_s | The video's length in seconds. |
video_width | Top Ads: the video's width in pixels. |
video_height | Top Ads: the video's height in pixels. |
media_expires_at | When the signed media links stop working (UTC). downloadMedia stores copies that do not expire. |
first_shown | The ad's first day shown (library). Null where TikTok gives an ad that never ran a placeholder (the moment of the query as both dates). |
last_shown | The ad's last day shown so far (library). |
days_shown | Days from the first to the last day shown, both counted. |
is_active | Still running, by TikTok's own status (tiktok_status) when the run knows it; otherwise last shown today or yesterday and not removed. |
tiktok_status | TikTok's own status of a library ad: active or inactive, as its Ad Library filter lists it (TikTok serves the status as a filter, not a field; an ad last shown yesterday can be inactive). Null where the run could not tell. |
launched_last_7_days | First shown less than 7 days ago. |
launched_last_30_days | First shown less than 30 days ago. |
long_running | Shown for 30 days or more. |
posted_at | creators rows: when the creator posted it (UTC). |
audit_status | The library's audit state: approved or removed. |
is_removed | TikTok removed the ad. The reason is in removal_reasons (detail). |
removal_reasons | Why TikTok removed the ad, in its words (library detail). |
display_mode | The library's display mode of the ad (standard, enhanced). |
reach_bucket | Unique users reached, as the library's band ("10K-100K"). |
reach_min | The reach band's lower bound, as a number. |
reach_max | The reach band's upper bound, as a number (null for an open band such as "100K+"). |
impressions_by_country | Reach per country, most first: country (ISO-2), impressions as TikTok writes it ("313K" or a band "1K-10K"), impressions_estimate as a number, impressions_min / impressions_max the band's bounds. |
top_country | The country with the most reach (library) or the Top Ads list's country. |
countries_count | How many countries the ad was shown in. |
regions | ISO-2 codes of the countries the ad was shown in — the shape our Google, Meta and LinkedIn ads actors use. |
audience_breakdown | Reach per country × age × gender where TikTok publishes it: country, age, gender, impressions (null where TikTok shows "-"). |
target_audience_size | The targeted audience's size, as the library's band ("21.8M-26.6M"). |
audience_size_min | The audience-size band's lower bound, as a number. |
audience_size_max | The audience-size band's upper bound, as a number. |
targeting_ages | Age groups targeted in any country (13-17 … 55+). |
targeting_genders | Genders targeted in any country (female, male, unknown). |
targeting_by_country | Per country: country, ages and genders targeted there. |
targeting_interests | Interest categories targeted. |
targeting_video_interactions | Video-interaction categories targeted. |
targeting_creator_interactions | Creator-interaction categories targeted. |
targeting_custom_audience | Whether a custom audience was targeted. |
targeting_custom_audience_excluded | Whether a custom audience was excluded. |
targeting_countries | Countries in the targeting settings. |
targeting_cities | Cities targeted. |
targeting_provinces | Provinces or regions targeted. |
targeting_languages | Languages targeted. |
targeting_devices | Device models targeted. |
targeting_os | Operating systems targeted. |
targeting_spending_power | The high-spending-power setting, when used. |
video_views_bucket | creators rows: the post's views, as the library's band. |
video_views_min | creators rows: the views band's lower bound. |
video_views_max | creators rows: the views band's upper bound. |
rank | Top Ads: the position in the list, in topAdsSortBy order (1 = first). Spotlight: the page's order. |
top_ads_country | Top Ads: the country of the list the ad came from. |
top_ads_period | Top Ads: the period of that list, in days (7, 30 or 180). |
ctr_top_percent | Top Ads: TikTok's CTR rank bucket, as a percentage — 6 means "CTR Top 6%". Lower is better; it is not a click-through rate. |
likes | Top Ads: likes. |
comments | Top Ads: comments (detail). |
shares | Top Ads: shares (detail). |
cost_level | Top Ads: TikTok's budget tier for the ad (1 = low … 3 = high). |
is_search_ad | Top Ads: shown in TikTok search. |
source | Top Ads: TikTok's source label for the ad (detail). |
keyword_list | Top Ads: keywords TikTok attaches to the ad (detail). |
pattern_labels | Top Ads: TikTok's creative-pattern label ids (detail). |
voice_over | Top Ads: the video has a voice-over (detail). |
highlight_text | Top Ads: TikTok's own note on the ad — on Spotlight ads, why its creative team picked it. |
keyframes | Top Ads (topAdsMetrics): per-second curves ctr, cvr, clicks, conversions, retention, each a list of second, value (TikTok's relative values). |
keyframe_highlights | Top Ads (topAdsMetrics): the seconds TikTok marks on each curve (ctr, cvr, …), a list of seconds per curve. |
percentiles | Top Ads (topAdsMetrics): the ad's percentile against other ads for ctr, cvr, clicks, conversions, impressions (0–1). |
copy_length | The caption's length in characters. |
text_language | The caption's language by a word vote (ISO 639-1); null when too short to tell. |
sentiment_score | The caption's sentiment, −1 to 1, from the AFINN word list — English captions only. |
analysis_angle | tagAds: the persuasion angle (problem_solution, social_proof, scarcity, discount, feature, lifestyle, curiosity, education, comparison, brand, other). |
analysis_cta_intent | tagAds: what the ad asks for (purchase, signup, download, learn_more, contact, visit, watch, apply, book, other). |
analysis_tone | tagAds: the tone (playful, urgent, professional, friendly, luxurious, informative, emotional, bold, other). |
analysis_sentiment | tagAds: the caption's sentiment, −1 to 1. |
analysis_offer_type | tagAds: what is offered (discount, giveaway, app_or_game, entertainment, physical_product, free_tool_or_trial, event_or_webinar, product_announcement, … other). |
analysis_funnel_stage | tagAds: awareness, consideration or conversion. |
analysis_confidence | tagAds: the confidence (0–1) of each tag, by tag name. |
analysis_hook | analyzeAds: the line meant to stop the scroll. |
analysis_offer | analyzeAds: the concrete offer, or null. |
analysis_audience | analyzeAds: who the ad is written for. |
analysis_strategy | analyzeAds: what the advertiser is doing with this ad, in one sentence. |
ad_ocr_text | ocrImageAds: the words in an image ad's artwork. |
transcript | transcribeVideos: what the video says. |
transcript_language | transcribeVideos: the spoken language (ISO 639-1). |
hook_3s | transcribeVideos: the words spoken in the first three seconds of speech. |
speech_seconds | transcribeVideos: seconds of speech in the video. |
transcript_segments | transcribeVideos: the transcript in timed segments (start, end, text). |
media_files | downloadMedia: the stored files — kind, key, url (does not expire), bytes, content_type, source_url, reused. |
image_file_url | downloadMedia: the stored first image or cover. |
video_file_url | downloadMedia: the stored video. |
detail_status | ok (the detail record is on the row), skipped (details off), not_found, or failed: … (not billed for details). |
matched_query | The search that found the row (the advertiser, keyword, creator, URL or Top Ads list). |
claimed_count | TikTok's own total for that search (library), or the Top Ads list's total. |
claimed_count_is_capped | The total is TikTok's 5,000 ceiling for a keyword: the real number is at least that. |
scraped_at | When the row was read (UTC). |
first_seen_at | Monitoring: the day a run of this search first saw the ad. |
last_seen_at | Monitoring: the last day a run saw it. |
ended_at | ended rows: the day a complete walk no longer listed the ad. |
times_seen | Monitoring: on how many days a run of this search saw the ad. |
previous_rank | Monitoring, Top Ads: the ad's rank the last time it was delivered. |
change_type | Monitoring: new, changed (delivered before, a watched field moved) or unchanged. |
changed_fields | Monitoring: which fields moved (last_shown, reach_bucket, audit_status, likes, ctr_top_percent). |
run_tag | Your runTag, on every row. |
search_query | count and advertiser_match rows: the library page of that search. |
has_ads | count and advertiser_match rows: whether the search finds any ad. |
exact_name_match | advertiser_match rows: TikTok's name is exactly the name you gave. |
report_country_share | advertiser rows: TikTok's report of where the advertiser's ads ran — country, share (0–1). |
report_ads_published_by_month | advertiser rows: ads published per month — month, ads. |
report_ads_published | advertiser rows: ads published in the window. |
report_first_published | advertiser rows: the first day with a new ad in the window. |
report_last_published | advertiser rows: the last day with a new ad in the window. |
summary_ad_count | Summary rows: ads counted. |
summary_active_count | advertiser_profile: of those, still running. |
summary_removed_count | advertiser_profile: of those, removed by TikTok. |
summary_longest_days | advertiser_profile: the longest run in days. |
summary_formats | advertiser_profile: ads per format. |
summary_landing_domains | Summary rows: the landing domains. |
summary_countries | advertiser_profile: ads per country. |
summary_distinct_copies | advertiser_profile: distinct captions. |
summary_ad_ids | Summary rows: the ad ids counted. |
summary_advertisers | hashtag rows: the advertisers using the hashtag. |
Example record:
{"row_type": "ad","surface": "library","creative_id": "1844346308991089","ad_url": "https://library.tiktok.com/ads/detail/?ad_id=1844346308991089","ad_format": "video","creative_available": true,"advertiser_name": "Notion","advertiser_id": "7377365644930662401","advertiser_location": "United Kingdom","payer": "Notion","advertiser_tiktok_username": null,"advertiser_tiktok_name": null,"advertiser_tiktok_url": null,"advertiser_tiktok_followers": null,"advertiser_tiktok_avatar_url": null,"advertiser_tiktok_account_type": null,"creator_username": null,"creator_url": null,"content_label": null,"body_text": "@Defender’s Boutique Camp was more than a retreat - it was a world of its own.","hook_text": "@Defender’s Boutique Camp was more than a retreat - it was a world of its own.","hashtags": null,"mentions": ["defender"],"cta": null,"cta_type": null,"objective": null,"objectives": null,"category": "News & Entertainment","industry": null,"industry_id": null,"destination_url": "https://www.tiktok.com/@notion/video/7551792476881751318?is_from_webapp=1&sender_device=pc&web_id=7554424558355465750&utm_source=tiktok&utm_medium=paid&utm_id=__CAMPAIGN_ID__&utm_campaign=__CAMPAIGN_NAME__","landing_domain": "tiktok.com","image_url": "https://p16-common-sign.tiktokcdn.com/tos-alisg-p-0051c001-sg/okPWCkwIiLBAaoCi2hACX0yRxpAAmBA0E8KufQ~tplv-tiktokx-origin.jpeg?dr=14582&refresh_token=3fa73c35&x-expires=1790784000&x-signature=KofWPhpCoCr2Lm6PG9MCxXwaob8%3D&t=4d5b0474&ps=13740610&shp=0c75dd76&shcp=9b759fb9&idc=sg1","image_urls": ["https://p16-common-sign.tiktokcdn.com/tos-alisg-p-0051c001-sg/okPWCkwIiLBAaoCi2hACX0yRxpAAmBA0E8KufQ~tplv-tiktokx-origin.jpeg?dr=14582&refresh_token=3fa73c35&x-expires=1790784000&x-signature=KofWPhpCoCr2Lm6PG9MCxXwaob8%3D&t=4d5b0474&ps=13740610&shp=0c75dd76&shcp=9b759fb9&idc=sg1"],"cover_url": "https://p16-common-sign.tiktokcdn.com/tos-alisg-p-0051c001-sg/okPWCkwIiLBAaoCi2hACX0yRxpAAmBA0E8KufQ~tplv-tiktokx-origin.jpeg?dr=14582&refresh_token=3fa73c35&x-expires=1790784000&x-signature=KofWPhpCoCr2Lm6PG9MCxXwaob8%3D&t=4d5b0474&ps=13740610&shp=0c75dd76&shcp=9b759fb9&idc=sg1","video_url": "https://library.tiktok.com/api/v1/cdn/1790764331/video/aHR0cHM6Ly92NzcudGlrdG9rY2RuLmNvbS8wZTQ3ODMwY2JkYWRmOWIyYjNjYjFjY2RiZDgwMTgzYi82YWJkMzk5YS92aWRlby90b3Mvbm8xYS90b3Mtbm8xYS12ZS01MWM3MTAtbm8vb29aUkN0ZUZJdlVMQ09rQWNBQWdySUFmYkVLUkdEQUVHZTdSNGcv/b3b2ff51-3545-4a5d-ae78-e2328d56ab8b?a=475769&bt=814&btag=e000b8000&bti=PDU2NmYwMy86&ft=.NpOcInz7Th23B4GXq8Zmo&l=2026093018321101F0A5CA4E082F289691&mime_type=video_mp4&rc=NzloZ2g6ZDk5NTRmODQ2N0BpM2lwZnE5cmVmNjMzODYzNEAwMTU1LzM1XzIxNi8vNDVhYSMvYGtvMmQ0Zl9hLS1kMC1zcw%3D%3D&signature=lKcTGI0By%2FyCgmuDqrJulCX7LOtLAj5XBo1Nxh81QJM%3D&vvpl=1","video_urls": [{"quality": null,"url": "https://library.tiktok.com/api/v1/cdn/1790764331/video/aHR0cHM6Ly92NzcudGlrdG9rY2RuLmNvbS8wZTQ3ODMwY2JkYWRmOWIyYjNjYjFjY2RiZDgwMTgzYi82YWJkMzk5YS92aWRlby90b3Mvbm8xYS90b3Mtbm8xYS12ZS01MWM3MTAtbm8vb29aUkN0ZUZJdlVMQ09rQWNBQWdySUFmYkVLUkdEQUVHZTdSNGcv/b3b2ff51-3545-4a5d-ae78-e2328d56ab8b?a=475769&bt=814&btag=e000b8000&bti=PDU2NmYwMy86&ft=.NpOcInz7Th23B4GXq8Zmo&l=2026093018321101F0A5CA4E082F289691&mime_type=video_mp4&rc=NzloZ2g6ZDk5NTRmODQ2N0BpM2lwZnE5cmVmNjMzODYzNEAwMTU1LzM1XzIxNi8vNDVhYSMvYGtvMmQ0Zl9hLS1kMC1zcw%3D%3D&signature=lKcTGI0By%2FyCgmuDqrJulCX7LOtLAj5XBo1Nxh81QJM%3D&vvpl=1"}],"video_id": null,"video_duration_s": null,"video_width": null,"video_height": null,"media_expires_at": "2026-09-30T16:00:00Z","first_shown": "2025-09-26","last_shown": "2025-10-03","days_shown": 8,"is_active": false,"tiktok_status": "inactive","launched_last_7_days": false,"launched_last_30_days": false,"long_running": false,"posted_at": null,"audit_status": "approved","is_removed": false,"removal_reasons": null,"display_mode": "standard","reach_bucket": "10K-100K","reach_min": 10000,"reach_max": 100000,"impressions_by_country": [{"country": "GB","impressions": "78K","impressions_estimate": 78000}],"top_country": "GB","countries_count": 1,"regions": ["GB"],"audience_breakdown": null,"target_audience_size": "10.6M-12.9M","audience_size_min": 10600000,"audience_size_max": 12900000,"targeting_ages": ["18-24","25-34","35-44","45-54"],"targeting_genders": ["female","male","unknown"],"targeting_by_country": [{"country": "GB","ages": ["18-24","25-34","35-44","45-54"],"genders": ["female","male","unknown"]}],"targeting_interests": ["Music"],"targeting_video_interactions": null,"targeting_creator_interactions": ["Fashion & Beauty"],"targeting_custom_audience": false,"targeting_custom_audience_excluded": null,"targeting_countries": null,"targeting_cities": null,"targeting_provinces": null,"targeting_languages": null,"targeting_devices": null,"targeting_os": null,"targeting_spending_power": null,"video_views_bucket": null,"video_views_min": null,"video_views_max": null,"rank": null,"top_ads_country": null,"top_ads_period": null,"ctr_top_percent": null,"likes": null,"comments": null,"shares": null,"cost_level": null,"is_search_ad": null,"source": null,"keyword_list": null,"pattern_labels": null,"voice_over": null,"highlight_text": null,"keyframes": null,"keyframe_highlights": null,"percentiles": null,"copy_length": 78,"text_language": null,"sentiment_score": null,"analysis_angle": null,"analysis_cta_intent": null,"analysis_tone": null,"analysis_sentiment": null,"analysis_offer_type": null,"analysis_funnel_stage": null,"analysis_confidence": null,"analysis_hook": null,"analysis_offer": null,"analysis_audience": null,"analysis_strategy": null,"ad_ocr_text": null,"transcript": null,"transcript_language": null,"hook_3s": null,"speech_seconds": null,"transcript_segments": null,"media_files": null,"image_file_url": null,"video_file_url": null,"detail_status": "ok","matched_query": "Notion","claimed_count": 221,"claimed_count_is_capped": false,"scraped_at": "2026-09-30T10:32:09Z","first_seen_at": null,"last_seen_at": null,"ended_at": null,"times_seen": null,"previous_rank": null,"change_type": null,"changed_fields": null,"run_tag": null,"search_query": null,"has_ads": null,"exact_name_match": null,"report_country_share": null,"report_ads_published_by_month": null,"report_ads_published": null,"report_first_published": null,"report_last_published": null,"summary_ad_count": null,"summary_active_count": null,"summary_removed_count": null,"summary_longest_days": null,"summary_formats": null,"summary_landing_domains": null,"summary_countries": null,"summary_distinct_copies": null,"summary_ad_ids": null,"summary_advertisers": null}
Pricing
Pay only for what a run actually returns, with no start fee and no platform usage billed to you. Prices are per 1,000 and fall with your Apify plan:
| per 1,000 | Free | Starter | Scale | Business |
|---|---|---|---|---|
Ad (ad) | $0.80 | $0.68 | $0.56 | $0.40 |
Ad detail record on that ad (ad_details) | +$1.20 | +$1.02 | +$0.84 | +$0.60 |
Top Ads curves and percentiles (ad_metrics) | +$2.00 | +$1.70 | +$1.70 | +$1.70 |
Count row (resultType counts or advertisers) (count) | $10.00 | $8.50 | $7.00 | $5.00 |
Advertiser report (advertiser) | $4.00 | $3.40 | $2.80 | $2.00 |
Typed tags on that ad (ad_tags) | +$1.00 | +$0.85 | +$0.70 | +$0.50 |
Written analysis of that ad (ad_analysis) | +$6.00 | +$5.10 | +$4.20 | +$3.00 |
Video transcript on that ad (ad_transcript) | +$20.00 | +$17.00 | +$15.00 | +$12.50 |
Image text read on that ad (ad_ocr) | +$2.00 | +$1.70 | +$1.40 | +$1.00 |
Stored image or cover (media_file) | $4.00 | $3.40 | $2.80 | $2.00 |
Stored video (media_video) | $20.00 | $17.00 | $15.00 | $14.00 |
An ad with its detail record is $2.00 per 1,000 on the Free plan and $1.00 on Business. Each fee is charged per row that actually carries the thing: a detail record that could not be read is delivered marked (detail_status) and not billed for details; a silent video is not billed a transcript; a file an earlier run stored is linked, not billed again; a search with no ads is a free zero. maxAds is exact and never overshot. Nothing is billed for a run that failed. Enterprise plans have their own rates — the Actor's Pricing tab shows the price for your plan.
Usage patterns
- Follow a competitor weekly — Put its name (or
Name | id) inadvertisers, tickonlyNewAds, save it as a task and schedule it. The first run delivers the current set; every later run only what appeared or changed since. For the change feed, open the task's Integrations tab and add a webhook on "Run succeeded" (or the Slack or email integration): it receives the run's dataset, which holds only the new and changed ads. Ready-made: Monitor a competitor's new TikTok ads weekly. - Find the ads worth copying —
minDaysRunning: 30keeps the ads an advertiser has run for a month or more;topAdsCountrieswithtopAdsSortBy: ctrgives TikTok's own best performers in a market. AddtagAdsto see which angle and offer they use,transcribeVideosfor the script. Ready-made: TikTok's top-performing US ads, transcribed and tagged. - Map a market — A keyword with
countries,agesandreach, or Top Ads withtopAdsIndustriesandtopAdsSweep.summaryRowsadds one profile per advertiser, one row per landing page and one per hashtag. Ready-made: TikTok ads that reached 100K+ users in Germany and France. - Know who advertises under a name —
resultType: advertiserswith a name returns every business id TikTok lists for it, whether the name matches exactly, and how many ads each runs — then pin the one you want withName | id. - Use a search you already set up — Set the filters on library.tiktok.com/ads or on the Creative Center's Top Ads page, copy the URL into
startUrls. Every filter in it is kept: an advertiser, a keyword search, the "other commercial content" tab of a creator, a Top Ads list or one ad. A published Google Sheet or a text file with one URL per line works as well. - Compare against their Google, Meta and LinkedIn ads — Run the same competitor through our Google Ads Transparency, Meta Ad Library and LinkedIn Ad Library scrapers. The four outputs share their core columns (
creative_id,ad_url,advertiser_name,advertiser_id,body_text,destination_url,first_shown,last_shown,days_shown,image_url,ad_format), so the rows stack in one sheet on those; the other columns are each platform's own.
Input configuration
| field | type | default | what it does |
|---|---|---|---|
advertisers | array | [] | Each entry is one advertiser in TikTok's Ad Library: its name as TikTok lists it (Samsung Electronics GmbH), or the name with its business id (`Notion |
keywords | array | [] | Words searched across every advertiser's ads, as the library's search box does. Put a phrase in double quotes ("running shoes") for the exact phrase. TikTok's total for a keyword stops at 5,000; the run walks past it by splitting the date window. |
creators | array | [] | TikTok usernames (vikaglam, @vikaglam or the profile URL): their posts in the library's "other commercial content" tab — branded posts with the commercial-content label. Read per country (countries, or all 32 when empty). |
startUrls | array | [] | URLs copied from the browser: a library search on library.tiktok.com/ads (an advertiser or a keyword search; every filter in it is kept), a library ad (/ads/detail/?ad_id=…), a creator on the "other commercial content" tab, a Creative Center Top Ads list or ad page, or the Top Ads Spotlight page. A text file, CSV or published Google Sheet with one URL per line works too (Link remote text file). |
adIds | array | [] | Ads to fetch again by id: library ad ids (16 digits, 1844346308991089) or Creative Center Top Ads ids (19 digits starting with 7), or their URLs. Each comes with its full record; an id TikTok no longer has comes back as a free not_found row. |
searches | array | [] | Several searches in one run, each with its own filters and cap. Each entry names one of advertiser, keyword, url or creator, plus any of countries, dateRange, startDate, endDate, timezone, adStatus, mediaType, ages, gender, reach, sortBy, maxAds. Example: `[{"advertiser": "Notion |
resultType | ads / counts / advertisers | "ads" | counts answers "does this advertiser run ads, and how many" from one call per search; a search with no ads is free. advertisers looks names up: each business id TikTok lists for the name, whether it is an exact match, and its number of ads. |
countries | array | [] | Ads shown in these countries: the library covers the EU, EEA, Switzerland and the UK. Empty = all 32 in one search. Several are one search each, deduplicated (an ad shown in two is delivered once). |
dateRange | last-7-days / last-30-days / last-90-days / last-year / custom | "last-year" | When the ad was shown, as the library's own date filter, in timezone. startDate / endDate win over this preset when you set them. |
startDate | string | YYYY-MM-DD. With an end date or alone (then the 12 months before the end date). Set dates win over dateRange. | |
endDate | string | YYYY-MM-DD. A date after today is today. | |
timezone | string | "UTC" | The IANA time zone the date window is read in (Europe/Berlin, America/New_York): a day runs midnight to midnight there. |
adStatus | all / active / inactive | "all" | The library's own status filter. The library page shows active ads by default; this Actor returns all by default. |
mediaType | all / video / image | "all" | The library's ad-type filter. |
ages | array | [] | Ads targeted at these age groups (the library's audience filter). Empty = any. |
gender | all / female / male | "all" | The library's audience gender filter. |
reach | array | [] | Ads whose reach falls in these bands (the library's reach filter). Empty = any. |
sortBy | newest / oldest / created_newest / created_oldest / impressions_high / impressions_low | "newest" | The order ads come in when a cap cuts the list. A walk that reaches the end of the list delivers every ad whatever the order. |
includeRemovedAds | boolean | true | Removed ads stay in the library with their removal reason (is_removed, removal_reasons, on the detail). Off: dropped before any detail is read, and not billed. |
minDaysRunning | integer | 0 | Keep ads shown for at least this many days (first to last shown day) — the long runners. 0 = all. Filtered on the list, before any detail. |
onlyActive | boolean | false | Keep only the ads TikTok itself lists as active (its status filter; an ad last shown yesterday can be inactive) and not removed. |
topAdsCountries | array | [] | The Creative Center's Top Ads (TikTok's best-performing ads, worldwide) for these countries: one list per country, deduplicated. Setting one runs Top Ads; leave empty for the Ad Library only. |
topAdsPeriod | 7 / 30 / 180 | "30" | The Top Ads period. |
topAdsSortBy | for_you / ctr / like / impression / play_2s_rate / play_6s_rate / cvr | "ctr" | TikTok's own order of the list. for_you changes between sessions; ctr is stable. rank on each row is the position in this order. |
topAdsIndustries | array | [] | Creative Center industries by name (Apparel & Accessories, Games) or id. The 258 names are TikTok's own. |
topAdsObjectives | array | [] | Campaign objectives to keep. |
topAdsLanguages | array | [] | Ad languages to keep. |
topAdsFormat | all / video / image | "all" | TikTok's own format filter. |
topAdsLikes | all / top_20 / top_40 / top_60 / top_80 / top_100 | "all" | TikTok's likes tier filter. |
topAdsKeyword | string | Keep Top Ads whose title or brand contains these words. TikTok answers keyword searches only to logged-in users, so the run reads the lists (with the sweep on) and matches the words itself. | |
topAdsSweep | boolean | false | Logged out, the Creative Center serves 20 ads per list. On: the run also reads the list under every sort, both directions, each objective, likes tier, format, industry and language, and deduplicates — more than 100 of TikTok's ~130 for one country and period. Each extra list is one call (about 64 per country). |
topAdsSpotlight | boolean | false | Also return the Spotlight: the ads TikTok's creative team hand-picked, with their note on why each works. |
topAdsDetails | boolean | true | On: each Top Ad carries its landing page, countries, comments, shares, objectives and source. Off: the list fields only. |
topAdsMetrics | boolean | false | Each Top Ad also carries TikTok's per-second curves (CTR, conversion rate, clicks, conversions, retention) and its five percentiles. Ten calls per ad. |
includeDetails | boolean | true | On: the targeting (age, gender, interests, audience size, languages, devices…), reach per country and the age × gender breakdown, the landing page with its UTMs, category, objective, CTA, payer and the advertiser's TikTok account. Off: the list fields only (dates, reach band, caption, media) — cheaper and faster. |
includeAdvertiserReport | boolean | false | One advertiser row per business id the run met: TikTok's own report of where its ads ran (share per country) and how many it published each month. |
downloadMedia | none / images / all | "none" | TikTok's media links expire (media_expires_at). Store the files in the run's key-value store and get links that do not; a file an earlier run stored is linked, not fetched or billed again. |
tagAds | boolean | false | Typed tags from the caption and CTA: angle, CTA intent, tone, offer type, funnel stage and sentiment, each with its confidence (analysis_*). Same tags as our LinkedIn and Meta ads actors. |
analyzeAds | boolean | false | The hook, the offer, who it is for and the advertiser's strategy, written by a model from the ad's words. |
ocrImageAds | boolean | false | The words set in the artwork of image ads (ad_ocr_text), read by a vision model. |
transcribeVideos | boolean | false | What the video says (transcript, its language, the first 3 seconds as hook_3s). A silent video is not billed. |
openaiApiKey | string | Your own key for analyzeAds, ocrImageAds and transcribeVideos, if you want the model usage on your account. Not needed: the Actor has its own. | |
summaryRows | boolean | false | Free rows after the ads: one profile per advertiser (ads, still running, longest run, formats, domains, countries), one per landing page and one per caption hashtag. |
outputFormat | full / compact | "full" | compact is for sheets and AI agents; billing is the same. |
maxAds | integer | 0 | Ads delivered in the whole run, exactly (0 = no limit). Never exceeded, and you are never billed for more. |
maxAdsPerSearch | integer | 0 | Ads per advertiser, keyword, creator, URL or Top Ads list (0 = no limit). |
onlyNewAds | boolean | false | Monitoring: skip every ad an earlier run with the same searches delivered — not returned, not charged. An ad whose last shown day, reach band, status or likes changed comes back with change_type: changed. |
includeEndedAds | boolean | false | Monitoring: a free ended row for each ad an earlier run saw that a complete walk of the same search no longer lists. |
stateStoreName | string | Name of the memory onlyNewAds and includeEndedAds keep between runs. Empty = derived from the searches, so the same task always meets its own memory. | |
runTag | string | Your own label, copied onto every row (run_tag). | |
resumeFromRunId | string | The id of a run of this Actor with the same input that stopped early (timeout, abort): this run continues where it stopped, without delivering or billing its ads again. |
FAQ
Why does advertisers not take a business id alone?
TikTok's library pins an advertiser by its registered name and its business id together: with the id and no name it answers every advertiser, with the id and another name it answers none (measured 2026-09-30). Give the name as TikTok registers it — the run finds its ids — or Name | id from a row's advertiser_name and advertiser_id, or paste the library URL of the advertiser's page.
Which countries does the library cover, and what about the US?
TikTok's Ad Library covers ads shown in the EU, EEA, Switzerland and the UK — 32 countries. Ads shown only elsewhere are not in it. The Creative Center's Top Ads cover 28 countries including the US, but only TikTok's top-performing ads, 20 per list logged out (more with topAdsSweep).
Why are some library rows without a video or images?
TikTok withholds the creative of some ads, active ones included, and removes the media of ads it took down. creative_available says which; is_removed and removal_reasons say when TikTok removed the ad.
How complete is an advertiser's list?
The walk runs to the end of TikTok's list, past its 5,000-row ceiling by splitting the date window, and reads the list in both directions because ads with the same date reshuffle between pages. The run summary compares what was listed with TikTok's own total per search and says complete true or false; claimed_count on every row is that total.
What is ctr_top_percent?
TikTok's CTR rank bucket from the Creative Center, as a percentage: 6 means the ad is in the top 6% by click-through rate. Lower is better. It is not a click-through rate, and some tools read it backwards.
What does a row cost me, and what if a detail fails?
Per ad, and per detail record read. A detail that could not be read is delivered marked (detail_status) and not billed for details. maxAds is exact. Nothing is billed for a run that failed.
Integration
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('hyperbach/tiktok-ad-library-scraper').call({"advertisers": ["Samsung Electronics GmbH"], "maxAds": 100});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python
from apify_client import ApifyClientclient = ApifyClient('YOUR_TOKEN')run = client.actor('hyperbach/tiktok-ad-library-scraper').call(run_input={'advertisers': ['Samsung Electronics GmbH'], 'maxAds': 100})items = client.dataset(run['defaultDatasetId']).list_items().items
CLI
$apify call hyperbach/tiktok-ad-library-scraper --input '{"advertisers": ["Samsung Electronics GmbH"], "maxAds": 100}'
REST
curl -X POST "https://api.apify.com/v2/acts/hyperbach~tiktok-ad-library-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H 'Content-Type: application/json' -d '{"advertisers": ["Samsung Electronics GmbH"], "maxAds": 100}'
Support
This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.