TikTok Ad Library scraper artworkCommercial Content Library

TikTok Ad Library Scraper.

Collect TikTok ads in the EU/EEA, UK and Switzerland. Watch the videos, compare offers and advertiser activity, and use what you find to plan tests for your own audience.

Run on Apify

Ways to use this scraper.

Try these examples for marketing, growth and competitor research.

01

Plan a video test around a product category

For a beauty campaign in France, collect ads in the category and watch the available videos. Tag opening hooks, demonstrations and offers yourself, then choose angles to test with your audience.

Use a research sheet to keep the references and shortlist storyboard ideas.

02

Research creative before entering another market

Compare public ads in Germany and Spain. Check which advertisers appear, the assets they use and the languages in the creatives before deciding what to produce locally.

Keep source videos in a market brief, along with the localization questions you still need to answer.

03

Find creators in a brand's commercial content

Search a brand name and check whether each record belongs to the brand's registered entity or a creator handle. Keep both identities when you save the results.

Use the advertiser and creator list for partnership research.

FROM FIRST RUN TO REPEATABLE WORKFLOW

Your first run, step by step.

  1. Open the Actor on Apify, select its Input tab and switch to the JSON editor if you want to paste a configuration.
  2. Replace the full JSON input with the example and change Nike to your advertiser. A display name can match several legal names; switch to advertiserBusinessIds after checking the business ID in a returned record.
  3. Select one supported country such as FR and maxAds 50. Keep residential proxies enabled. Remove the form’s prefilled GB region if you want France only. Leave audience filters unset until this first search works.
  4. Start the run and watch the log. Check which targets and filters were actually read before assuming an empty result means nothing exists.
  5. Open Storage → Dataset, inspect several records and export JSON for nested data or CSV for a first spreadsheet review.
First-run configuration
{
  "searchTerms": ["Nike"],
  "regions": ["FR"],
  "maxAds": 50,
  "adStatus": "all",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Paste this into the Actor’s JSON input editor. Replace the example targets with yours before running.

Check the current input form on Apify

Choose how to search.

This is TikTok’s Commercial Content Library, covering the EU/EEA, the UK and Switzerland. It is the right tool for advertiser research in those markets. For US creative inspiration, use the Creative Center scraper instead.

Search methodWhen to use itWhat changes
Advertiser or brand nameWhen to use itYou have a competitor watchlist.What changesSearch advertiser names, often registered legal entities rather than brand labels. Partial names, TikTok profiles and websites can resolve to a brand. A name with no ads may fall back to a keyword search.
Keyword discoveryWhen to use itYou want to find relevant results before choosing specific targets.What changesSearch ad content for themes such as running shoes, independently of advertiser identity. Use this to discover companies you do not already track.
Advertiser IDsWhen to use itYou know the exact entity you want to collect.What changesTikTok’s numeric business identifiers. Use these for exact advertiser tracking without name matching. Copy an ID from a verified source record; do not substitute a TikTok username.
Ad Library URLsWhen to use itYou already configured the search on the source website.What changesPaste search links from library.tiktok.com. Their countries, dates, status and audience filters take precedence; the separate input fields fill missing values.

The difference that matters

Only the 32 listed markets are covered: EU/EEA, UK and Switzerland. Explicit countries run separately. An empty regions list searches all covered markets together; ["all"] searches each country separately. Unsupported countries are skipped. If none remain, the search covers all supported markets.

Compare the related scraper

Every input, explained.

Use the exact field names below in JSON. In Apify’s form, enter list items separately, choose filters, and keep numbers and booleans in their proper types.

Default and prefill are different. A default applies when you omit a setting; a prefill is an example already entered in Apify’s form. Review prefilled targets and limits before every run. Some settings have no schema default. You still need to supply at least one supported target.

Targets and search inputs5
searchTerms
ListForm prefill: ["Nike"]

Search advertiser names, often registered legal entities rather than brand labels. Partial names, TikTok profiles and websites can resolve to a brand. A name with no ads may fall back to a keyword search.

searchTerm
Text

One advertiser name instead of a searchTerms list. Use the list for several competitors and an advertiserBusinessIds value when the exact entity is already known.

keywords
List

Search ad content for themes such as running shoes, independently of advertiser identity. Use this to discover companies you do not already track.

advertiserBusinessIds
List

TikTok’s numeric business identifiers. Use these for exact advertiser tracking without name matching. Copy an ID from a verified source record; do not substitute a TikTok username.

adLibraryUrls
List

Paste search links from library.tiktok.com. Their countries, dates, status and audience filters take precedence; the separate input fields fill missing values.

Markets, dates and filters10
regions
ListForm prefill: ["GB"]

Only the 32 listed markets are covered: EU/EEA, UK and Switzerland. Explicit countries run separately. An empty regions list searches all covered markets together; ["all"] searches each country separately. Unsupported countries are skipped. If none remain, the search covers all supported markets.

Suggested JSON values
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 all
region
Text

One country alongside or instead of regions. Unlike Google Ads, this single-country field is combined with the list rather than only filling an empty list.

Suggested JSON values
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
minDate
Text

Filters the date an ad was last shown, server-side. It is not a creation-date filter. Use YYYY-MM-DD; empty dates cover the library’s available archive rather than its website’s default 30-day view.

maxDate
Text

Last-shown dates must be on or before this day. Combine with minDate for a last-delivery window; an ad first launched months earlier can still match.

adType
TextDefault: all

Choose all, video, image or text. This filters the creative format; it does not choose political versus commercial ads.

Suggested JSON values
all video image text
adStatus
TextDefault: all

active means running now, inactive means stopped, all includes both. Status and last-shown dates answer different questions, so set both deliberately.

Suggested JSON values
all active inactive
sortBy
TextDefault: last_shown_date,desc

Choose last-shown date, publication date or unique reach, ascending or descending. With a maxAds cap, sorting changes which portion of the matching ads you collect first.

Suggested JSON values
last_shown_date,desc last_shown_date,asc create_time,desc create_time,asc impression,desc impression,asc
gender
TextDefault: ALL

Filters the advertiser’s declared target gender: ALL, FEMALE or MALE. This is targeting metadata, not a measured breakdown of the people who actually watched the ad.

Suggested JSON values
ALL FEMALE MALE
ages
List

Target-age bands, as a list of strings. Use the comma-separated band values below, for example 18,24. Empty means every age; these are declared targets rather than measured viewers.

Suggested JSON values
all 13,17 18,24 25,34 35,44 45,54 55,100
adReach
List

Keep ads in selected public reach bands: 0-10K, 10K-100K or 100K+. Empty means all bands. Do not read a band as an exact impression or conversion count.

Suggested JSON values
all 0-10K 10K-100K 100K+
Limits, details and proxies5
proxyConfiguration
ObjectDefault: {"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}Form prefill: {"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}

Residential proxies are required. Datacenter exits can fail during session setup without an obvious blocking message. Keep the default RESIDENTIAL group before changing filters or dates to diagnose a failed run.

maxAds
IntegerForm prefill: 500

A hard cap on unique ads across the whole run, including all targets and markets. Start with 50. Leaving it empty removes this cap; a broad search can then become much larger.

maxPages
Integer

Limits pages for each country-search job. The effective page size is at most 12 ads, even if older descriptions mention larger batches. Clear for full pagination within your result cap.

pageSize
IntegerDefault: 12

1-12 ads per request. Values above 12 are read as 12 because TikTok caps its page size. Increasing maxPages changes depth; increasing pageSize beyond 12 does not.

delayMs
IntegerDefault: 500

Pause between page requests, in milliseconds. Increase it when the source throttles you; reducing it does not remove network delays or the source’s rate limits.

Advanced settings and recovery4
raw
True or falseDefault: false

Returns TikTok’s untouched records. Unlike the normal output, dates are not converted and encoded media URLs are not decoded. Keep false for a spreadsheet-ready dataset.

proxyRotations
IntegerDefault: 3

Retries refused work with a new proxy session. More retries can recover temporary blocks but add time and traffic. Keep the default until the log shows a reason to change it.

resume
True or falseDefault: true

Saves progress about every 30 seconds so an Apify restart or migration can continue the current run. Leave it on for normal use.

continueFromLastRun
True or falseDefault: false

Continues unfinished work from the previous run with matching input. Earlier results remain in that run’s dataset. Keep false for a fresh collection or a recurring snapshot.

This reference follows the Actor’s published input fields. Check the live form before changing a production workflow. Check the current input form on Apify.

Configurations you can copy.

Each example is a separate run. Start small, inspect the results, then increase coverage. Update the targets, countries and dates to match your question.

Track one advertiser’s active ads

Collect up to 50 active ads shown in the UK. Check legal advertiser names in the output before scheduling. Keep the same country and filters for each weekly snapshot.

Track one advertiser’s active ads
{
  "searchTerms": ["Nike"],
  "regions": ["GB"],
  "adStatus": "active",
  "maxAds": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Explore a specific creative segment

Look for skincare video ads in France targeting ages 25 to 34 with the 100K+ reach band. These filters can produce a small or empty sample. Remove reach and age filters one at a time if you need broader discovery.

Explore a specific creative segment
{
  "keywords": ["skincare"],
  "regions": ["FR"],
  "adType": "video",
  "ages": ["25,34"],
  "adReach": ["100K+"],
  "sortBy": "last_shown_date,desc",
  "maxAds": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Compare delivery across two countries

Search Germany and France with a last-shown date window. The same ad can appear in both searches and is kept once. Do not add up country counts from this deduplicated output as though they were separate ad inventories.

Compare delivery across two countries
{
  "searchTerms": ["Nike"],
  "regions": ["DE", "FR"],
  "minDate": "2026-09-01",
  "maxDate": "2026-09-30",
  "maxAds": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Run, check, export, repeat.

Keep the ad ID, legal advertiser name, source URL, media and first/last shown dates. Reach may be a band, while spend and impression fields may be empty. These records do not show conversions or prove an ad worked. Save media references promptly because URLs can expire, and keep country-search context when building comparisons.

  1. Check the dataset and the run’s SUMMARY record. Compare the number collected with your cap, inspect failed or skipped inputs, and verify a few original source links.
  2. Keep the original IDs and add collected_at and run_id when saving results. Export CSV for flat columns; retain JSON when arrays or nested details matter.
  3. Save the tested configuration as an Apify Task and schedule it. For repeated snapshots, leave continueFromLastRun false. Deduplicate new records by source ID while retaining each observation date.
  4. In Make or n8n, wait for a successful run, fetch its dataset and map fields into Sheets or your warehouse. Send records to Looker Studio through a reporting table; use dbt to flatten and test warehouse models.
  5. The same JSON works with Apify’s Actor API. In Claude with Apify MCP, name this Actor, ask it to inspect the live schema, and give explicit targets, markets and result limits before it runs.

Resume is not a fresh snapshot

resume protects the current run if Apify restarts it. continueFromLastRun continues an earlier run with the same configuration; earlier records stay in the earlier dataset. Combine both datasets for the complete collection, and raise a previously reached result cap when continuing. Start fresh when you want to see what changed today.

Follow the Sheets, Claude, Looker and BigQuery setup guides
Run this Actor from the API

Save one configuration above as input.json. Set APIFY_TOKEN to your Apify API token in your terminal, then send the file as the request body.

Start the run
curl --fail-with-body --request POST \
  --url "https://api.apify.com/v2/actors/jmlp~tiktok-ad-library-scraper/runs" \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @input.json

The response contains a run ID and defaultDatasetId, not finished results. Wait for the run to succeed, set DATASET_ID to that dataset ID, then fetch its items. For large datasets, use limit and offset to page through the export.

Fetch the dataset
curl --fail-with-body \
  --url "https://api.apify.com/v2/datasets/$DATASET_ID/items?format=json" \
  --header "Authorization: Bearer $APIFY_TOKEN"

Apify’s run and export API reference
Dataset export options

When the results look wrong.

Change one setting at a time, keep a small cap, and check the run summary before scaling up.

The selected country returns no useful results.

Only the 32 listed markets are covered: EU/EEA, UK and Switzerland. Explicit countries run separately. An empty regions list searches all covered markets together; ["all"] searches each country separately. Unsupported countries are skipped. If none remain, the search covers all supported markets.

The source keeps returning empty pages or access errors.

Residential proxies are required. Datacenter exits can fail during session setup without an obvious blocking message. Keep the default RESIDENTIAL group before changing filters or dates to diagnose a failed run.

Why are spend or performance fields empty?

Keep the ad ID, legal advertiser name, source URL, media and first/last shown dates. Reach may be a band, while spend and impression fields may be empty. These records do not show conversions or prove an ad worked. Save media references promptly because URLs can expire, and keep country-search context when building comparisons.

The run succeeded but returned nothing

Success means the Actor finished handling the request, not that the source returned data. Check SUMMARY.inputProblem, SUMMARY.problem and the log for missing targets, unsupported filters or refused requests. Test one known target with fewer filters.

Fewer records than expected

Check the global limit, per-search or per-page limits, platform coverage and deduplication. Several searches can find the same record. A source’s headline count can include records the public endpoint does not return. Review unfinished jobs before treating the dataset as complete.

Use the results in your tools.

Google Sheets

Append ad_id, advertiser_name, scraped_region, first_shown, last_shown and media_url. Watch the videos before adding labels for hooks, formats and product angles.

Read the setup
Claude + MCP

Ask Claude to organize the metadata and cite the source records. For video analysis, give it the media or a transcript through a supported workflow. Metadata alone won't show the opening hook.

Read the setup
Looker Studio

Compare ad activity by advertiser and region. Keep reach as a band, and don't add repeated regional observations together as though they were unique people.

Read the setup
BigQuery + dbt

Keep raw observations and a creative table keyed by ad_id. Store regional observations separately and retain the original reach bands.

Read the setup
Copy a prompt for Claude
Prompt for Claude + Apify MCP
Check the schema of jmlp/tiktok-ad-library-scraper and collect up to 50 Nike-related records in FR. Separate advertiser entities from creator handles, summarize delivery dates and available reach bands, and cite ad_library_url. Flag unavailable spend and impression data. Do not describe video content you have not inspected.

The fields you’ll get.

Keep the collection time and original IDs with your records. You’ll need them to check where a result came from or compare it with a later run.

Before you draw conclusions

This scraper covers 32 supported markets in the EU/EEA, UK and Switzerland. Spend and impression fields can be empty; estimated_audience contains available reach bands. Those bands and dates do not show conversions or ROAS. Media links can expire.

ad_id / advertiser_business_id
Stable identifiers for records and repeat advertiser tracking.
advertiser_name
The reported account; creator names may appear for branded content.
first_shown / last_shown
Reported delivery dates in the selected country.
media_url / cover_url
Available media and preview image links.
estimated_audience
The public reach band reported by the library.
scraped_region / ad_library_url
Collection context and a source reference.

Common questions.

Can I scrape the US TikTok ad market?

This Actor targets the official Commercial Content Library’s supported markets in the EU/EEA, UK and Switzerland. It does not provide US or worldwide ad coverage.

Can Claude automatically understand the videos?

The scraper returns media links and metadata. Video-content analysis needs access to the actual media or a transcript and a compatible analysis workflow.

Source and current product details: JMLP’s TikTok Ad Library Actor on Apify.

Other scrapers
you might use.

Let’s talk about
your project.

Tell me what you need to collect or understand. I can help with a custom scraper, a pipeline or the analysis.

Start a project