TikTok's official Ad Library API is the Commercial Content API. You apply for it, and it returns only ads from EU countries, 10 per request. Our API reads the public TikTok Ad Library instead: ads shown in the EEA, the UK, Switzerland and Turkey, 12 a call, each with a link to its video file.
What TikTok's Commercial Content API gives you
The Commercial Content API is TikTok's documented source for its ad library, and it needs an approved application. Its query endpoint returns each ad's first and last shown dates, video URL, the advertiser's business_name, and reach as unique_users_seen, at most 10 ads per request. If you are approved and only need EU ads, use it.
Search the TikTok Ad Library with ToolzerHub
We make ToolzerHub. Our TikTok Ads API searches the library by region, a date window in Unix seconds, and a query. Every call is a GET with the x-api-key header and costs 1 credit.
export TOOLZERHUB_API_KEY=your_key
END=$(date +%s); START=$((END - 30 * 86400))
curl -H "x-api-key: $TOOLZERHUB_API_KEY" \
"https://api.toolzerhub.com/v1/tiktok-ads/search?region=GB&query=nike&start_time=$START&end_time=$END"
The first of 12 ads that came back, trimmed:
{
"id": "1877122884181393",
"name": "lianalastique",
"title": "@Nike #nike #sports ",
"first_shown_date": 1790121600000,
"last_shown_date": 1790121600000,
"estimated_audience": "0-1K",
"subject": "Apparel & Accessories",
"videos": [{ "video_url": "https://library.tiktok.com/api/v1/cdn/1792604592/video/..." }]
}
The response also holds total, has_more and a search_id; send search_id with offset=12 for the next page. A total of 5000 means "at least". Dates are in milliseconds, and reach comes as a band such as 0-1K or 1M-10M.
The ad above is not from Nike. A plain query matches ad text, and the first two pages for nike in the UK held 23 different ads: 19 from creator accounts whose posts mention Nike, 4 from NIKE Retail B.V.
Search one advertiser's ads
To get a brand's own ads, look up its advertiser id, then search by it. /v1/tiktok-ads/suggestions?query=nike returns advertisers with ids, among them NIKE COM SRL, NIKE Retail B.V. and NIKELAB LTD. Passing search_type=advertiser and advertiser_id=6876453864464188162 returned 12 of 12 ads from NIKE Retail B.V., out of 1,961 UK ads in 30 days. Pick the entity that runs ads in your country: for the Netherlands, IKEA's is IKEA B.V.
Download an advertiser's ad videos
The script looks up the advertiser by exact name, pages through its ads up to a page limit, saves each ad's first video as <ad id>.mp4 and writes ads.csv.
import csv
import os
import sys
import time
from datetime import datetime, timezone
import requests
BASE = "https://api.toolzerhub.com/v1/tiktok-ads"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["ad_id", "advertiser", "title", "first_shown", "last_shown", "reach", "video_file"]
VIDEO_HEADERS = {"User-Agent": "Mozilla/5.0"} # the video host 403s requests' default one
def get(path, params, tries=3):
# 429, 500 and 503 are retried with a growing pause; failed calls cost no credits.
for attempt in range(tries):
r = requests.get(f"{BASE}/{path}", headers=HEADERS, params=params, timeout=90)
if r.status_code in (429, 500, 503) and attempt < tries - 1:
time.sleep(10 * (attempt + 1))
continue
r.raise_for_status()
return r.json()["data"]
def advertiser_id(name):
found = get("suggestions", {"query": name})["data"]["adv_names"]
for adv in found:
if adv["name"].lower() == name.lower():
return adv["ids"]
sys.exit("No exact match. TikTok suggests: " + "; ".join(a["name"] for a in found))
def ads(name, region, days, pages):
end = int(time.time())
params = {"region": region, "query": name, "search_type": "advertiser",
"advertiser_id": advertiser_id(name), "start_time": end - days * 86400,
"end_time": end}
for page in range(pages):
data = get("search", params)
yield from data.get("data") or []
if not data.get("has_more"):
return
params.update(search_id=data["search_id"], offset=(page + 1) * 12)
def day(ms):
return datetime.fromtimestamp(ms / 1000, timezone.utc).date().isoformat()
def main(name, region, days="30", pages="2", folder="tiktok_ads"):
os.makedirs(folder, exist_ok=True)
with open(os.path.join(folder, "ads.csv"), "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
saved = 0
seen = set()
for ad in ads(name, region.upper(), int(days), int(pages)):
if ad["id"] in seen: # the next page can repeat an ad
continue
seen.add(ad["id"])
video = ""
for video_info in ad.get("videos") or []: # some ads carry no video
video = f"{ad['id']}.mp4"
with requests.get(video_info["video_url"], headers=VIDEO_HEADERS, stream=True,
timeout=120) as r:
r.raise_for_status()
with open(os.path.join(folder, video), "wb") as out:
for chunk in r.iter_content(1 << 16):
out.write(chunk)
saved += 1
break
writer.writerow({"ad_id": ad["id"], "advertiser": ad["name"],
"title": (ad.get("title") or "").strip(),
"first_shown": day(ad["first_shown_date"]),
"last_shown": day(ad["last_shown_date"]),
"reach": ad.get("estimated_audience"), "video_file": video})
print(f"{len(seen)} ads, {saved} videos saved to {folder}/")
if __name__ == "__main__":
if len(sys.argv) < 3:
sys.exit('usage: python tiktok_ad_videos.py "IKEA B.V." NL [days] [pages] [folder]')
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
python tiktok_ad_videos.py "IKEA B.V." NL 30 2 made 3 calls and printed 23 ads, 23 videos saved to tiktok_ads/ after 51 seconds. IKEA B.V. had 47 ads in that window, and the run stopped at the 2 pages asked for.
The 23 files came to 108.2 MB: 8.5 to 82 seconds long, 17 of them 576x1024. 18 of the 23 ads had no title, and their reach ran from 10K-100K to 1M-10M.
Which countries the library covers
The Ad Library search covers ads shown in the EEA, the UK, Switzerland and Turkey, and region=US is not available. For the US, use Creative Center's Top Ads: /v1/tiktok-ads/top-ads/list?country_codes=US returned 10 of TikTok's best-performing ads with click-through rate, likes and video links from 360p to 1080p. These are top performers TikTok picks, not every ad a brand runs. Download videos soon after a search rather than storing the links.
What it costs
Each call is 1 credit and a search call returns up to 12 ads, so 1,000 ads is one advertiser lookup plus 84 search calls: 85 credits. Video files come from TikTok's servers and use no credits. The 100 free credits a month cover a first test; $19 buys 10,000 credits that never expire, and plans for higher volume cover more brands. Set your key and the first advertiser's ads are on disk in under a minute.
LinkedIn has no such API either; see the LinkedIn Ad Library API guide. The same job on Meta has its own guide: download videos from the Meta Ad Library, and the Meta Ad Library API post compares Meta's official route. For TikTok's other approval-only API, see TikTok Research API access.
We are not affiliated with TikTok or ByteDance.