TikTok Ads Scraper - Ad Library by Keyword and Country
Pricing
from $0.45 / 1,000 ad scrapeds
TikTok Ads Scraper - Ad Library by Keyword and Country
Scrape TikTok ads from TikTok's public Ad Library. Search by keyword, advertiser, country or date. Each ad gives the advertiser, caption, and first and last shown dates. You also get countries targeted, a viewer count band, video, thumbnail, CTA and landing URL. EEA and UK ads only, no US.
Pricing
from $0.45 / 1,000 ad scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Share
TikTok Ads Scraper: ads from TikTok's public Commercial Content Library
Search TikTok's own ad archive by keyword, advertiser, country and date, and get one flat row per ad: who ran it, the caption, the first and last dates it was shown, the countries it ran in, the audience band TikTok publishes, the video and thumbnail, the button text and the landing page.
Read the coverage line before you plan anything around this. The archive exists because of EU and UK transparency rules, so it holds the EEA plus GB, CH, NO, IS and LI, and nothing before 2022-10-01. There is no United States edition of this library, and no spend or performance figures in it.
| Input | Search terms, advertiser names, or links from library.tiktok.com/ads |
| Output | One row per ad |
| Ceiling | 20,000 ads per run, and 20 terms, 20 advertisers and 20 links |
| Account needed | None |
| Price | $0.45 per 1,000 ads, flat on every plan |
📣 What TikTok Ads Scraper does
Four ways to say what you want, and they combine in one run.
A keyword matches advertiser names and ad copy, so running shoes returns every ad whose text
mentions running shoes.
An advertiser name is resolved against the library's own register first, then that advertiser's
ads are pulled. Typing a brand word like Nike picks up every registered entity whose name starts
with it, and the row keeps your wording in searchTerm.
A library link pasted straight from the site: the country, dates, advertiser, order and format already in the address are read back out and used as they are.
Countries on their own, with no search term, means every ad running in those countries.
📥 What you give it
{"searchTerms": ["running shoes", "protein powder"],"countries": ["DE", "FR", "IT"],"dateFrom": "2026-07-01","dateTo": "2026-08-15","maxItems": 100,"includeAdDetails": true}
| Field | Starts at | What it is |
|---|---|---|
searchTerms | box holds running shoes | Keywords. Up to 20, and the row budget is split evenly between every target. |
advertiserNames | empty | Registered names like NIKE Retail B.V., or a brand word. |
adLibraryUrls | empty | Addresses copied from the library site. |
countries | box holds DE | Two-letter codes, or all. Only these exist in the library: 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. |
dateFrom, dateTo | empty | YYYY-MM-DD. Left empty it covers the last 30 days. Anything earlier than 2022-10-01 is moved forward to it. |
maxItems | box holds 20 | Total ads across every target, up to 20,000. |
includeAdDetails | on | Fetches the per-ad transparency record. It is the only source of landingUrl, callToAction, advertisingObjective, advertiserRegistryCountry, countriesTargeted, targetAudienceSize and impressionsByCountry. |
adFormat | all | all, video, image or text. |
adStatus | all | all, active for still running, inactive for stopped. |
sortBy | create_time,desc | Published date newest first is the order the library repeats and skips least. Last-shown and unique-users orders are there too. |
proxyUrls | empty | Optional. Your own servers, as http://user:pass@host:port, used exactly as given. |
sessionCookies | empty | Optional and almost never needed. Your own TikTok sessionid, as a safety net if the archive stops serving signed-out readers. Anyone holding that value can act as your account, so treat it like a password. |
Run it with the input empty and you get one labelled sample row and nothing else.
📤 What you get back
One flat row per ad. These are the fields, read off the deployed output schema.
| Field | What it is |
|---|---|
adId, adDetailUrl | The library's own id, and the link back to that ad's page. |
advertiserName, advertiserId | Who ran it. paidBy is filled when a sponsor is named separately. |
caption | The ad copy as the archive holds it. |
firstShownDate, lastShownDate | Day granularity, ISO format. |
countriesTargeted, searchedRegions | Where the ad ran, and which countries your search covered. |
uniqueUsersSeen, targetAudienceSize, impressionsByCountry | Bands, not numbers. TikTok publishes ranges. |
videoUrl, thumbnailUrl, imageUrls | Links only, and they are signed and expire. Download what you want to keep. |
landingUrl, callToAction, advertisingObjective | Where the ad clicks through to, the button text, and the campaign objective. |
adFormat, adStatus | video, image or text, and active, inactive or rejected. |
targetedAgeGroups, targetedGenders | Only what the archive publishes, which is not every ad. |
searchTerm | Which of your terms, advertisers or links produced the row. |
🧾 Reading the output
Three kinds of row can land in your dataset.
| Row | How to spot it |
|---|---|
| An ad | ok: true and recordType: "ad" |
| The sample row | _sample: true, written only when the input was empty |
| A diagnostic | ok: false, _diagnostic: true and an errorCode |
charged: true marks a real ad row and false marks a sample or diagnostic one. Read it as the row
type: it is stamped as the row is built, so it is not a receipt. Your run's own event count in Apify
is the billing record.
| Code | What it means |
|---|---|
BAD_INPUT | A country code that does not exist in this library, a date outside it, or a link the Actor cannot read. |
NO_RESULTS | Nothing matched. On an advertiser name it usually means no registered match, so try it as a keyword. |
RATE_LIMITED | The library kept answering "system busy" for that search. Worth a re-run with a narrower window. |
NETWORK | The library was unreachable or answered badly. |
TIME_BUDGET | The run ran out of time before reaching that target. |
PROXY_INPUT_ADJUSTED | Something you put in proxyUrls was unusable, so the run carried on without it. |
CHARGE_ERROR | A charge could not be recorded. A couple in a row stops the run. |
▶️ How to run it
- Open TikTok Ads Scraper and click Try for free.
- Put your keywords into Search terms, or names into Advertiser names, or paste library links into Ad Library URLs.
- Set Ad target countries to the codes you care about, and a Shown from and Shown until date if the last 30 days is not the window you want.
- Set Maximum rows low, around 20, for the first run, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$0.45 per 1,000 ads. Flat on every Apify plan, no volume tiers.
You are charged per ad row delivered. Ads already seen earlier in the same run are dropped before that, so a creative matching two of your terms costs once. The sample row, every diagnostic row and a country code or date the library does not support are not charged.
💡 What people use it for
- Watching what a competitor is running right now in a given market, by advertiser name.
- Pulling a category's creatives by keyword and reading the captions and calls to action together.
- Tracking how long an ad stays up, using
firstShownDateandlastShownDateacross scheduled runs. - Collecting landing pages for a set of advertisers to see where the traffic is being sent.
- Building a picture of which countries an advertiser targets, from
countriesTargeted.
🚧 What it does not do
- No United States ads. The archive covers the EEA plus GB, CH, NO, IS and LI, and nothing before 2022-10-01. This is the library's own scope.
- No spend and no performance data. Reach and impressions come back as bands, because bands are what TikTok publishes.
- A failed detail lookup leaves fields null, and the row does not say so.
landingUrl,countriesTargeted,advertiserRegistryCountry,targetAudienceSize,impressionsByCountry,targetedAgeGroupsandtargetedGenderscan be null either because the archive has no value or because that one lookup did not come back. Treat a null as "unknown", not "none". - An unsupported country next to a search term widens the search. Ask for a country the library
does not have and the run searches every country it does have, with one uncharged
BAD_INPUTrow to tell you. ChecksearchedRegionson the rows before you read a country breakdown. - Media is linked, not downloaded. Those links are signed and expire.
- 12 rows a page. A large
maxItemsis many round trips, so give a big run room. - Ordering by last shown repeats and skips ads, which is why published-date order is the starting point.
🧭 Which TikTok scraper do you need?
| If you want | Use |
|---|---|
| Ads from the public Commercial Content Library | This one |
| Videos under a hashtag | TikTok Hashtag Scraper |
| Comments under a video | TikTok Comments Scraper |
| Follower counts and profile stats | TikTok Profile Scraper |
| Products and units sold on TikTok Shop | TikTok Shop Scraper |
❓ Questions people ask
Do I need a TikTok account or an ad account? No. The library is a public transparency archive and the run reads it the way a signed-out visitor does.
Can I get US ads? No. There is no US edition of this library, so nothing in the world can pull them from it.
Why are some fields null on a row? Either the archive has no value, or the per-ad record did not come back that time. The row does not distinguish them, so re-run the ad if a null matters.
How far back does it go? 2022-10-01. Earlier dates are moved forward to it and you get an uncharged row telling you.
Can I run it on a schedule? Yes. adId is stable, so a daily run diffs cleanly against the last
one.
Is scraping the ad library legal? It is a public archive that TikTok publishes to meet transparency rules. Apify's write-up on scraping and the law is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the search, advertiser or link that misbehaved and
the run ID. The errorCode on the diagnostic row usually names the problem on its own.