Full adlibrary API Documentation and Implementation Guide
Complete guide to the AdLibrary API — search ads from Meta, TikTok, Google, and more programmatically. Includes authentication, endpoints, parameters, response formats, and integration examples. API access requires an active Business subscription. This is a living document and will be updated with further changes.
Sections
AdLibrary API Endpoint
The AdLibrary API lets you programmatically search ads across Facebook, Instagram, TikTok, Google and more. All requests go through a single base URL:
1https://adlibrary.com/api/search
All requests use POST with a JSON body.
Authentication
The API uses API key authentication. Include your key in the Authorization header with every request:
1Authorization: Bearer adl_your_api_key
• Business subscription required — API access is only available on the Business plan
• API keys are prefixed with adl_ and managed in your developer dashboard
• 1 credit per request — credits are deducted from your account balance
• Rate limits: 10 requests/minute, 10,000 requests/day
Getting Your API Key
Log into adlibrary.com, navigate to your developer settings, and create a new API key. Each key is shown once at creation — store it securely. You can revoke and create new keys at any time.
Pricing
Each API request costs 1 credit, the same as a GUI search. Every response includes a _credits object showing your remaining balance:
1{2 "_credits": {3 "used": 1,4 "remaining": 999,5 "autoCharged": false,6 "creditsAdded": 07 }8}
Search Endpoint
The primary endpoint for searching ads across all supported platforms.
1curl -X POST "https://adlibrary.com/api/search" \2 -H "Authorization: Bearer adl_your_key" \3 -H "Content-Type: application/json" \4 -d '{5 "keyword": "fitness app",6 "appType": "3",7 "geo": ["USA"],8 "daysBack": 30,9 "pageSize": 1010 }'
App Types
The appType parameter determines which ad category you are searching. It is required for every request.
• appType "3" — E-commerce & Brand ads (default). This is the most commonly used type.
• appType "1" — Gaming app ads. Supports app category and OS filters. Currently inactive (being rebuilt).
• appType "2" — Non-gaming app ads (Business, Education, Finance, etc.). Supports app category and OS filters. Currently inactive (being rebuilt).
Request Body Reference
All filters are passed as fields in the JSON request body. Here is the complete reference of all supported fields:
Search & Sort
1POST /api/search2{3 "keyword": "fitness app",4 "appType": "3",5 "searchType": "0",6 "preciseSearch": false,7 "sortField": "-impression",8 "daysBack": 309}
• keyword (string) — Search keyword
• excludeKeyword (string) — Exclude keyword from results
• appType (string, required) — Ad category: "1" (Gaming), "2" (Apps), "3" (E-commerce)
• searchType (string) — What field to search: "0" = All Text, "1" = Title, "4" = Body, "5" = Caption, "6" = Landing Page
• preciseSearch (boolean) — Set to false for broad match. Default is true (exact match).
• sortField (string) — Sort order. Valid values: -correlation (relevance), -first_seen (newest), -last_seen (recently active), -impression (most impressions), -like_count (most likes), -share_count (most shares), -comment_count (most comments), -days (longest running), -heat_degree (trending), -related_ads_count (most related ads)
• daysBack (number) — Filter by recency: 1, 3, 7, 14, 30, 60, 90, 180, or 365. Default is 90.
• dateFrom / dateTo (string, YYYY-MM-DD) — Custom date range. Takes priority over daysBack when set.
Targeting
• platform (string[]) — Filter by ad platform: "facebook", "instagram", "tiktok", "twitter", "pinterest", "yahoo", "unity_ads", "admob", "youtube"
• placement (string[]) — Filter by ad placement: "feed", "stories", "reels", "marketplace", "video_feeds", "search", "instream", "right_column", "instant_articles", "audience_network", "messenger"
• geo (string[], ISO 3166 alpha-3) — Target countries, e.g. ["USA", "GBR", "DEU"]. Supports 50+ countries.
• excludeGeo (string[]) — Exclude specific countries
• language (string[]) — Filter by ad language using ISO 639 codes: "en", "de", "fr", "es", "it", "pt", "nl", "ja", "ko", "zh-CN", "zh-TW", "ar", "hi", "th", "vi", "tr", and 20+ more
• os (string[]) — Filter by operating system: "1" = iOS, "2" = Android. Only applies to appType 1 and 2.
Creative
• adsType (string[]) — Media type: "1" = Image, "2" = Video, "3" = Carousel, "4" = Collection
• adsFormat (string[]) — Aspect ratio: "1:1", "16:9", "9:16", "4:5", "4:3"
• adsSize (string) — Video quality: "hd" or "sd"
• videoDurationBegin / videoDurationEnd (number, seconds) — Video duration range
• callToAction (string[], single value used) — Call-to-action category: "shopping", "transform" (conversions), "traffic_acquisition", "potential_customer" (leads), "interaction" (engagement), "other"
E-commerce Filters (appType 3)
• independentWebsite (string[]) — Filter by advertiser domain name
• ecommercePlatform (string[]) — Filter by store platform: "shopify", "bigcommerce", "opencart", "wordpress" (WooCommerce), "magento", "wix", "squarespace", "shop.tiktok.com"
App Category Filters (appType 1 and 2)
• tagIds (string[]) — App category IDs. Gaming (appType 1): 10–27 (Action, Adventure, Arcade, Board, Card, Casino, Casual, Educational, Music, Puzzle, Racing, Role Playing, Simulation, Sports, Strategy, Trivia, Word, Family). Non-gaming (appType 2): 51–72 (Books, Business, Communication, Dating, Education, Entertainment, Finance, Food, Health, Lifestyle, and more).
Engagement Filters
• likeBegin / likeEnd (number) — Filter by like count range
• shareBegin / shareEnd (number) — Filter by share count range
• commentBegin / commentEnd (number) — Filter by comment count range
Note: Impressions, views, heat, and running days only support sorting (via the sort parameter), not filtering by range.
Special Flags
• newAdsFlag (boolean) — New ads only
• originalFlag (boolean) — Original (first seen) ads only
• isDynamic (boolean) — Dynamic creative ads
• codFlag (boolean) — Cash on delivery ads
• duplicateRemoval (boolean or number) — Remove duplicate creatives (1 or 2 for different modes)
• searchArbitrageFlag (boolean) — Search arbitrage ads
• viewIllegal (boolean) — Include policy-violating ads
Pagination
• page (number) — Page number, starting at 1
• pageSize (number) — Results per page. Default is 60.
Complete Search Example
Here is a complete example with multiple filters:
1curl -X POST "https://adlibrary.com/api/search" \2 -H "Authorization: Bearer adl_your_key" \3 -H "Content-Type: application/json" \4 -d '{5 "keyword": "skincare",6 "appType": "3",7 "platform": ["facebook", "instagram"],8 "geo": ["USA", "GBR"],9 "adsType": ["2"],10 "sortField": "-impression",11 "daysBack": 30,12 "ecommercePlatform": ["shopify"],13 "likeBegin": 100,14 "pageSize": 2015 }'
Response Format
A successful search response looks like this:
1{2 "results": [3 {4 "ad_key": "abc123",5 "ads_type": 2,6 "advertiser_name": "Brand Name",7 "app_type": 3,8 "title": "Ad headline text",9 "body": "Ad body copy...",10 "message": "Main ad text",11 "caption": "Caption text",12 "button_text": "Shop Now",13 "like_count": 1250,14 "comment_count": 89,15 "share_count": 340,16 "view_count": 50000,17 "impression": 120000,18 "first_seen": 1719849600,19 "last_seen": 1720454400,20 "days_count": 7,21 "heat": 850,22 "preview_img_url": "https://...",23 "video_url": "https://...",24 "video_duration": 30,25 "page_name": "Brand Page",26 "page_id": "123456",27 "platform": "facebook",28 "geo": ["USA", "GBR"],29 "fb_merge_channel": ["feed", "stories"],30 "landing_page_url": "https://example.com/product",31 "ecommerce_platform": "shopify",32 "independent_website": "example.com",33 "related_ads_count": 1534 }35 ],36 "total": 4230,37 "page": 1,38 "pageSize": 20,39 "_credits": {40 "used": 1,41 "remaining": 998,42 "autoCharged": false,43 "creditsAdded": 044 }45}
Each ad object contains engagement metrics (like_count, comment_count, share_count, view_count, impression), date fields as Unix timestamps (first_seen, last_seen, created_at), media URLs, targeting data (geo, platform, fb_merge_channel), and e-commerce info when applicable. Additional fields may be present depending on the ad.
Each ad object contains engagement metrics (like_count, comment_count, share_count, view_count, impression), date fields as Unix timestamps (first_seen, last_seen, created_at), media URLs, targeting data (geo, platform, fb_merge_channel), and e-commerce info when applicable. Additional fields may be present depending on the ad.
Ad Detail Endpoint
Fetch detailed information about a specific ad, including audience analysis data when available. This endpoint does not require authentication and does not cost credits.
1curl -X POST "https://adlibrary.com/api/ad-detail" \2 -H "Content-Type: application/json" \3 -d '{4 "creative_key": "abc123",5 "app_type": "3"6 }'
Parameters
• creative_key (string, required) — The ad_key from a search result
• app_type (string, default "3") — The app type of the ad
• created_at (string, optional) — Unix timestamp. Defaults to current time if omitted.
Response
The response includes a detail object with extended engagement and cost data. When the ad has an associated page, an audience analysis breakdown is also returned:
1{2 "detail": {3 "ad_key": "abc123",4 "ad_cost": 5200,5 "associated_id": "page_assoc_id",6 "page_id": "123456",7 "like_count": 1250,8 "comment_count": 89,9 "share_count": 340,10 "view_count": 50000,11 "impression": 120000,12 "days_count": 7,13 "heat": 850,14 "countries": ["US", "GB"],15 "store_url": "https://example.com",16 "fb_merge_channel": ["feed", "stories"]17 },18 "audience": {19 "min_age": 18,20 "max_age": 65,21 "sex": "all",22 "total_reach": 850000,23 "sex_detail": [24 { "type": "male", "count": 425000, "percent": 50 },25 { "type": "female", "count": 425000, "percent": 50 }26 ],27 "age_detail": [28 {29 "type": "18-24",30 "count": 170000,31 "percent": 20,32 "male": 85000,33 "female": 85000,34 "unknown": 035 }36 ],37 "location_detail": [38 {39 "code": "US",40 "count": 595000,41 "percent": 70,42 "male": 297500,43 "female": 297500,44 "unknown": 045 }46 ]47 }48}
The audience object is only returned when the ad has both an associated_id and page_id. The detail object may include additional fields beyond those listed here. Responses are cached for 5 minutes.
Error Codes
The API uses standard HTTP status codes. All error responses include an error message and may include a code field:
• 400 Bad Request — Missing required parameters (e.g. creative_key for ad-detail)
• 401 Unauthorized — Missing or invalid API key
• 402 Payment Required — Insufficient credits. Response includes balance and creditsRequired fields.
• 403 Forbidden — Feature not available on your plan, or permission denied
• 429 Too Many Requests — Rate limit exceeded. Check the Retry-After header for seconds until reset.
• 500 Internal Server Error — Search failed. If credits were deducted, they are automatically refunded.
1// Example 402 error response2{3 "error": "Insufficient credits",4 "code": "INSUFFICIENT_CREDITS",5 "creditsRequired": 1,6 "balance": 0,7 "autoChargeEnabled": false8}910// Example 429 error response11{12 "error": "Rate limit exceeded. Maximum 100 requests per minute.",13 "code": "RATE_LIMIT_EXCEEDED",14 "retryAfter": 4515}
API Key Management
Manage your API keys via the developer endpoints. These endpoints require a web session (cookie auth) — they cannot be called with an API key.
List Keys
1POST /api/developer/keys2// empty body34// Response5{6 "keys": [7 {8 "id": "uuid",9 "name": "Production Key",10 "key_prefix": "adl_abc12345",11 "is_active": true,12 "last_used_at": "2025-06-01T12:00:00Z",13 "requests_today": 42,14 "requests_this_month": 1250,15 "created_at": "2025-01-15T10:00:00Z"16 }17 ]18}
Create Key
1POST /api/developer/keys2{ "name": "My Integration Key" }34// Response (the secret is only shown once!)5{6 "key": {7 "id": "uuid",8 "name": "My Integration Key",9 "key_prefix": "adl_abc12345",10 "is_active": true,11 "secret": "adl_full_key_value_here"12 },13 "message": "API key created successfully. Save this key - it won't be shown again!"14}
Delete Key
1POST /api/developer/keys/{id}/delete23// Response4{ "success": true, "message": "API key revoked successfully" }
Update Key
1POST /api/developer/keys/{id}2{ "name": "Renamed Key", "is_active": false }34// Response5{6 "key": {7 "id": "uuid",8 "name": "Renamed Key",9 "key_prefix": "adl_abc12345",10 "is_active": false,11 "last_used_at": "2025-06-01T12:00:00Z",12 "created_at": "2025-01-15T10:00:00Z"13 },14 "message": "API key updated successfully"15}
You can create up to 10 API keys per account. Keys can be renamed, deactivated, or revoked permanently.
Credit System
Check your current credit balance:
1POST /api/credits2// empty body34// Response5{ "credits": 950 }
Each search costs 1 credit. If you search the same keyword within one hour (via the web UI), subsequent requests for that keyword are not charged again — this allows free pagination, re-sorting, and filter changes on the same query.
If a search fails after credits are deducted, the credit is automatically refunded. You can also enable auto-charge in your account settings to automatically purchase more credits when your balance runs low.
Javascript Example
1/**2 * AdLibrary API — Quick Start (Node.js)3 *4 * Search for ads and export results to CSV.5 * No dependencies required — uses built-in Node.js APIs.6 *7 * Usage:8 * node adlibrary-api-example.js9 */1011const fs = require("fs");1213// ── Configuration ───────────────────────────────────────────────────────────1415const API_KEY = "adl_YOUR_API_KEY_HERE"; // Replace with your API key16const BASE_URL = "https://adlibrary.com/api/search";17const OUTPUT_FILE = "ads_export.csv";1819// ── Search & Export ─────────────────────────────────────────────────────────2021const CATEGORIES = {22 Appliances: ["kitchen appliances", "Dyson", "KitchenAid", "Whirlpool"],23 Automotive: ["car accessories", "auto parts", "AutoZone", "Tesla"],24 "Arts & Crafts": ["art supplies", "craft supplies", "Cricut", "Canva"],25 "Baby Products": ["baby gear", "baby stroller", "Graco", "Pampers"],26 Beauty: ["skincare", "makeup", "Sephora", "The Ordinary", "Glossier"],27 Books: ["books online", "audiobooks", "Kindle", "Audible"],28 "Phones & Accessories": ["phone case", "smartphone", "Samsung Galaxy", "iPhone accessories"],29 "Clothing & Fashion": ["fashion", "clothing brand", "Shein", "Zara", "Nike apparel"],30 Music: ["headphones", "music streaming", "Spotify", "Bose"],31 "Office Supplies": ["office supplies", "desk accessories", "Staples", "HP printer"],32 Electronics: ["electronics", "laptop", "Sony", "Apple", "Samsung"],33 "Home & Kitchen": ["home decor", "kitchen gadgets", "IKEA", "Instant Pot"],34 "Health & Wellness": ["supplements", "vitamins", "fitness", "Athletic Greens"],35 "Lawn & Garden": ["garden tools", "outdoor furniture", "lawn care", "Husqvarna"],36 "Pet Supplies": ["dog food", "pet supplies", "Chewy", "BarkBox"],37 "Sports & Outdoors": ["sports equipment", "running shoes", "Nike", "Adidas"],38 "Toys & Games": ["toys", "board games", "LEGO", "Hasbro"],39 "Video Games": ["video games", "gaming", "PlayStation", "Xbox", "Nintendo"],40};4142const AD_TYPES = { 1: "Image", 2: "Video", 3: "Carousel", 4: "Collection" };4344const CSV_FIELDS = [45 "category", "search_term", "advertiser_name", "platform", "ad_type",46 "title", "body", "call_to_action", "impressions", "like_count",47 "comment_count", "share_count", "days_running", "first_seen",48 "last_seen", "landing_page", "preview_image", "ad_key",49];5051function tsToDate(ts) {52 if (!ts) return "";53 try { return new Date(ts * 1000).toISOString().slice(0, 10); }54 catch { return ""; }55}5657function escapeCsv(val) {58 const s = String(val ?? "");59 if (s.includes(",") || s.includes('"') || s.includes("\n")) {60 return `"${s.replace(/"/g, '""')}"`;61 }62 return s;63}6465function adToRow(ad, category, searchTerm) {66 return {67 category,68 search_term: searchTerm,69 advertiser_name: ad.advertiser_name || "",70 platform: ad.platform || "",71 ad_type: AD_TYPES[ad.ads_type] || String(ad.ads_type || ""),72 title: ad.title || "",73 body: ad.body || ad.message || "",74 call_to_action: ad.call_to_action || ad.button_text || "",75 impressions: ad.impression || ad.all_exposure_value || "",76 like_count: ad.like_count ?? "",77 comment_count: ad.comment_count ?? "",78 share_count: ad.share_count ?? "",79 days_running: ad.days_count ?? "",80 first_seen: tsToDate(ad.first_seen),81 last_seen: tsToDate(ad.last_seen),82 landing_page: ad.landing_page_url || ad.store_url || "",83 preview_image: ad.preview_img_url || "",84 ad_key: ad.ad_key || "",85 };86}8788async function searchAds(keyword, page = 1) {89 const res = await fetch(BASE_URL, {90 method: "POST",91 headers: {92 Authorization: `Bearer ${API_KEY}`,93 "Content-Type": "application/json",94 Accept: "application/json",95 "User-Agent": "AdLibrary-API-Client/1.0",96 },97 body: JSON.stringify({ keyword, appType: "3", page, pageSize: 60 }),98 });99100 if (res.status === 402) {101 const err = await res.json();102 console.log(` ✗ Out of credits. Balance: ${err.balance ?? "?"}`);103 return null;104 }105106 if (res.status === 429) {107 const wait = parseInt(res.headers.get("Retry-After") || "10");108 console.log(` ⏳ Rate limited. Waiting ${wait}s...`);109 await new Promise((r) => setTimeout(r, wait * 1000));110 return searchAds(keyword, page);111 }112113 if (!res.ok) {114 const err = await res.json().catch(() => ({}));115 console.log(` ✗ Error ${res.status}: ${err.error || "Unknown error"}`);116 return [];117 }118119 const data = await res.json();120 const results = data.results || [];121 const remaining = data._credits?.remaining ?? "?";122 console.log(` ✓ ${results.length} ads — ${remaining} credits remaining`);123 return results;124}125126async function main() {127 if (API_KEY === "adl_YOUR_API_KEY_HERE") {128 console.error("ERROR: Please set your API key in the script (API_KEY variable).");129 process.exit(1);130 }131132 const allRows = [];133 let creditsUsed = 0;134135 console.log(`AdLibrary Ad Research — ${Object.keys(CATEGORIES).length} categories\n`);136137 for (const [category, terms] of Object.entries(CATEGORIES)) {138 console.log(`📁 ${category}`);139140 for (const term of terms) {141 process.stdout.write(` Searching: "${term}"... `);142143 const results = await searchAds(term);144145 if (results === null) {146 console.log("\nStopping: no credits remaining.");147 break;148 }149150 for (const ad of results) {151 allRows.push(adToRow(ad, category, term));152 }153154 creditsUsed++;155 await new Promise((r) => setTimeout(r, 1000));156 }157 }158159 // Deduplicate160 const seen = new Set();161 const unique = allRows.filter((row) => {162 if (seen.has(row.ad_key)) return false;163 seen.add(row.ad_key);164 return true;165 });166167 // Write CSV168 const header = CSV_FIELDS.join(",");169 const lines = unique.map((row) =>170 CSV_FIELDS.map((f) => escapeCsv(row[f])).join(",")171 );172 fs.writeFileSync(OUTPUT_FILE, [header, ...lines].join("\n"), "utf-8");173174 console.log(`\nDone! ${unique.length} unique ads exported to ${OUTPUT_FILE}`);175 console.log(` Total fetched: ${allRows.length}, Dupes removed: ${allRows.length - unique.length}`);176 console.log(` Credits used: ~${creditsUsed}`);177}178179main().catch(console.error);180
Shell Example
1#!/bin/bash2#3# AdLibrary API — Quick Start (Shell/cURL)4#5# Search for ads and save the raw JSON response.6# Each request costs 1 credit and returns up to 60 ads.7#8# Usage:9# chmod +x adlibrary-api-example.sh10# ./adlibrary-api-example.sh1112API_KEY="adl_YOUR_API_KEY_HERE" # Replace with your API key13BASE_URL="https://adlibrary.com/api/search"1415# ── Single search ────────────────────────────────────────────────────────────16# Search for "Nike" ads and save the full JSON response1718echo "Searching for 'Nike' ads..."1920curl -s -X POST "$BASE_URL" \21 -H "Authorization: Bearer $API_KEY" \22 -H "Content-Type: application/json" \23 -H "Accept: application/json" \24 -H "User-Agent: AdLibrary-API-Client/1.0" \25 -d '{"keyword":"Nike","appType":"3"}' \26 -o nike_ads.json2728echo " ✓ Saved to nike_ads.json"2930# ── Pagination ───────────────────────────────────────────────────────────────31# Fetch page 2 of results (costs 1 additional credit)3233# curl -s -X POST "$BASE_URL" \34# -H "Authorization: Bearer $API_KEY" \35# -H "Content-Type: application/json" \36# -H "User-Agent: AdLibrary-API-Client/1.0" \37# -d '{"keyword":"Nike","appType":"3","page":2}' \38# -o nike_ads_page2.json3940# ── Batch search ─────────────────────────────────────────────────────────────41# Search multiple keywords and save each to a separate JSON file4243KEYWORDS=("skincare" "Samsung" "LEGO" "dog food" "running shoes")4445echo ""46echo "Batch searching ${#KEYWORDS[@]} keywords..."4748for keyword in "${KEYWORDS[@]}"; do49 filename="${keyword// /_}_ads.json"50 printf " Searching: %-20s" "\"$keyword\"..."5152 HTTP_CODE=$(curl -s -o "$filename" -w "%{http_code}" \53 -X POST "$BASE_URL" \54 -H "Authorization: Bearer $API_KEY" \55 -H "Content-Type: application/json" \56 -H "Accept: application/json" \57 -H "User-Agent: AdLibrary-API-Client/1.0" \58 -d "{\"keyword\":\"$keyword\",\"appType\":\"3\"}")5960 if [ "$HTTP_CODE" = "200" ]; then61 echo " ✓ → $filename"62 elif [ "$HTTP_CODE" = "402" ]; then63 echo " ✗ Out of credits"64 rm -f "$filename"65 break66 elif [ "$HTTP_CODE" = "429" ]; then67 echo " ⏳ Rate limited, waiting 10s..."68 rm -f "$filename"69 sleep 1070 else71 echo " ✗ Error $HTTP_CODE"72 rm -f "$filename"73 fi7475 sleep 176done7778echo ""79echo "Done! JSON files saved in current directory."80
Python Example
We have Cloudflare in front and it is blocking uncategorized python lib requests, so you need to use a user agent, which can be arbitrary - here is a complete working example that fetches categories and brands.
1"""2AdLibrary API — Category Ad Research Script3=============================================4Searches for ads across product categories and exports results to CSV.56Usage:7 python adlibrary-api-example.py89Configuration:10 - Set your API key below (API_KEY)11 - Adjust PAGES_PER_CATEGORY to control how many pages to fetch (1 page = 60 ads)12 - Each page costs 1 credit1314Output:15 - ads_export.csv in the current directory16"""1718import csv19import time20import urllib.request21import json22import sys2324# ── Configuration ────────────────────────────────────────────────────────────2526API_KEY = "adl_YOUR_API_KEY_HERE" # Replace with your API key27BASE_URL = "https://adlibrary.com/api/search"28PAGES_PER_CATEGORY = 1 # Pages per search term (60 ads/page, 1 credit/page). Increase for more results.29OUTPUT_FILE = "ads_export.csv"3031# ── Categories & Search Terms ────────────────────────────────────────────────32# Each category has a list of search terms — a mix of category keywords and33# top brands — to get broad coverage of that vertical.3435CATEGORIES = {36 "Appliances": ["kitchen appliances", "Dyson", "KitchenAid", "Whirlpool"],37 "Automotive": ["car accessories", "auto parts", "AutoZone", "Tesla"],38 "Arts & Crafts": ["art supplies", "craft supplies", "Cricut", "Canva"],39 "Baby Products": ["baby gear", "baby stroller", "Graco", "Pampers"],40 "Beauty": ["skincare", "makeup", "Sephora", "The Ordinary", "Glossier"],41 "Books": ["books online", "audiobooks", "Kindle", "Audible"],42 "Phones & Accessories": ["phone case", "smartphone", "Samsung Galaxy", "iPhone accessories"],43 "Clothing & Fashion": ["fashion", "clothing brand", "Shein", "Zara", "Nike apparel"],44 "Music": ["headphones", "music streaming", "Spotify", "Bose"],45 "Office Supplies": ["office supplies", "desk accessories", "Staples", "HP printer"],46 "Electronics": ["electronics", "laptop", "Sony", "Apple", "Samsung"],47 "Home & Kitchen": ["home decor", "kitchen gadgets", "IKEA", "Instant Pot"],48 "Health & Wellness": ["supplements", "vitamins", "fitness", "Athletic Greens"],49 "Lawn & Garden": ["garden tools", "outdoor furniture", "lawn care", "Husqvarna"],50 "Pet Supplies": ["dog food", "pet supplies", "Chewy", "BarkBox"],51 "Sports & Outdoors": ["sports equipment", "running shoes", "Nike", "Adidas"],52 "Toys & Games": ["toys", "board games", "LEGO", "Hasbro"],53 "Video Games": ["video games", "gaming", "PlayStation", "Xbox", "Nintendo"],54}5556# ── CSV Fields ───────────────────────────────────────────────────────────────57# Essential fields for dashboard use. The API returns many more fields —58# see the full API docs for the complete list.5960CSV_FIELDS = [61 "category",62 "search_term",63 "advertiser_name",64 "platform",65 "ad_type",66 "title",67 "body",68 "call_to_action",69 "impressions",70 "like_count",71 "comment_count",72 "share_count",73 "days_running",74 "first_seen",75 "last_seen",76 "landing_page",77 "preview_image",78 "ad_key",79]8081AD_TYPES = {1: "Image", 2: "Video", 3: "Carousel", 4: "Collection"}828384def timestamp_to_date(ts):85 """Convert a unix timestamp to YYYY-MM-DD, or return empty string."""86 if not ts:87 return ""88 try:89 return time.strftime("%Y-%m-%d", time.gmtime(int(ts)))90 except (ValueError, OSError):91 return ""929394def search_ads(keyword, page=1):95 """Call the AdLibrary search API. Returns (results_list, total_count)."""96 payload = json.dumps({97 "keyword": keyword,98 "appType": "3",99 "page": page,100 "pageSize": 60,101 }).encode()102103 req = urllib.request.Request(BASE_URL, data=payload, headers={104 "Authorization": f"Bearer {API_KEY}",105 "Content-Type": "application/json",106 "Accept": "application/json",107 "User-Agent": "AdLibrary-API-Client/1.0",108 })109110 try:111 resp = urllib.request.urlopen(req, timeout=120)112 data = json.loads(resp.read().decode())113 except urllib.error.HTTPError as e:114 body = e.read().decode()115 try:116 err = json.loads(body)117 except json.JSONDecodeError:118 err = {"error": body}119120 if e.code == 402:121 print(f" ✗ Out of credits. {err.get('error', '')}")122 print(f" Balance: {err.get('balance', '?')} credits remaining")123 return None, 0124 elif e.code == 429:125 wait = int(e.headers.get("Retry-After", 10))126 print(f" ⏳ Rate limited. Waiting {wait}s...")127 time.sleep(wait)128 return search_ads(keyword, page)129 else:130 print(f" ✗ Error {e.code}: {err.get('error', body[:200])}")131 return [], 0132 except Exception as e:133 print(f" ✗ Request failed: {e}")134 return [], 0135136 if data is None:137 return None, 0138139 results = data.get("results", [])140 total = data.get("total", 0)141 credits_info = data.get("_credits", {})142 remaining = credits_info.get("remaining", "?")143144 print(f" ✓ {len(results)} ads (total: {total}) — {remaining} credits remaining")145 return results, total146147148def ad_to_row(ad, category, search_term):149 """Extract essential fields from an ad into a flat dict for CSV."""150 return {151 "category": category,152 "search_term": search_term,153 "advertiser_name": ad.get("advertiser_name", ""),154 "platform": ad.get("platform", ""),155 "ad_type": AD_TYPES.get(ad.get("ads_type"), str(ad.get("ads_type", ""))),156 "title": ad.get("title", ""),157 "body": ad.get("body", "") or ad.get("message", ""),158 "call_to_action": ad.get("call_to_action", "") or ad.get("button_text", ""),159 "impressions": ad.get("impression", "") or ad.get("all_exposure_value", ""),160 "like_count": ad.get("like_count", ""),161 "comment_count": ad.get("comment_count", ""),162 "share_count": ad.get("share_count", ""),163 "days_running": ad.get("days_count", ""),164 "first_seen": timestamp_to_date(ad.get("first_seen")),165 "last_seen": timestamp_to_date(ad.get("last_seen")),166 "landing_page": ad.get("landing_page_url", "") or ad.get("store_url", ""),167 "preview_image": ad.get("preview_img_url", ""),168 "ad_key": ad.get("ad_key", ""),169 }170171172def main():173 if API_KEY == "adl_YOUR_API_KEY_HERE":174 print("ERROR: Please set your API key in the script (API_KEY variable).")175 sys.exit(1)176177 all_rows = []178 total_credits_used = 0179180 print(f"AdLibrary Ad Research — {len(CATEGORIES)} categories")181 print(f"Pages per category: {PAGES_PER_CATEGORY} (60 ads/page, 1 credit/page)")182 print(f"Estimated credits needed: ~{len(CATEGORIES) * len(list(CATEGORIES.values())[0]) * PAGES_PER_CATEGORY}")183 print("=" * 60)184185 for category, terms in CATEGORIES.items():186 print(f"\n📁 {category}")187188 for term in terms:189 for page in range(1, PAGES_PER_CATEGORY + 1):190 page_label = f" (page {page})" if PAGES_PER_CATEGORY > 1 else ""191 print(f" Searching: \"{term}\"{page_label}...", end=" ")192193 results, total = search_ads(term, page)194195 if results is None:196 # Out of credits — stop everything197 print("\nStopping: no credits remaining.")198 break199200 for ad in results:201 all_rows.append(ad_to_row(ad, category, term))202203 total_credits_used += 1204 time.sleep(1) # Be nice to the API205206 else:207 continue208 break # Break outer loop if inner loop broke (out of credits)209 else:210 continue211 break212213 if not all_rows:214 print("\nNo ads found. Check your API key and try again.")215 sys.exit(1)216217 # Deduplicate by ad_key (same ad can appear in multiple searches)218 seen = set()219 unique_rows = []220 for row in all_rows:221 if row["ad_key"] not in seen:222 seen.add(row["ad_key"])223 unique_rows.append(row)224225 # Write CSV226 with open(OUTPUT_FILE, "w", newline="", encoding="utf-8") as f:227 writer = csv.DictWriter(f, fieldnames=CSV_FIELDS)228 writer.writeheader()229 writer.writerows(unique_rows)230231 print("\n" + "=" * 60)232 print(f"Done! {len(unique_rows)} unique ads exported to {OUTPUT_FILE}")233 print(f" Total ads fetched: {len(all_rows)}")234 print(f" Duplicates removed: {len(all_rows) - len(unique_rows)}")235 print(f" Credits used: ~{total_credits_used}")236237238if __name__ == "__main__":239 main()240
Further Reading
Related Articles

Cross-Platform AI Marketing Tool AdLibrary.com Launches With Over 1 Billion Ads
The first tool to search ads across Facebook, Instagram, TikTok, Google, YouTube, Twitter (X), Pinterest and more — all in one place.

Meta Ad Library: The Complete Guide to Competitor Research
Learn how to use the Meta Ad Library for competitive intelligence. Discover how to analyze active ads, spot creative trends, and build better campaigns.

A Guide to Using Meta Ad Library for Competitive Intelligence
Step-by-step guide to using Meta's Ad Library for competitive intelligence. Search any brand's Facebook and Instagram ads, analyze creative trends, and build your swipe file.
Strategic Facebook Ads Management: A Comprehensive Guide for 2026
Master Facebook ads management with structured workflows for creative research, campaign setup, optimization, and scaling. The complete 2026 practitioner's guide.