Ad Library Scraping: Track Competitor Ads on Facebook, Google & LinkedIn
Every major ad platform now has a public ad library. Facebook, Google, and LinkedIn all let you see any advertiser's active ads. The problem? Their interfaces are slow, clunky, and impossible to use at scale.
With SociaVault's ad library endpoints, you can pull competitor ads programmatically, analyze creative patterns, track when ads go live and die, and spot messaging shifts before they're obvious.
Facebook Ad Library
Meta's Ad Library is the most comprehensive. Every active ad on Facebook and Instagram is visible, along with spending ranges for political ads.
Search for Competitor Ads
const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE = 'https://api.sociavault.com/v1/scrape';
const headers = { 'X-API-Key': API_KEY };
async function searchFacebookAds(query) {
const res = await fetch(
`${BASE}/facebook-ad-library?query=${encodeURIComponent(query)}`,
{ headers }
);
const ads = (await res.json()).data || [];
console.log(`\nFacebook Ad Library: "${query}" — ${ads.length} ads found\n`);
ads.slice(0, 10).forEach((ad, i) => {
console.log(`${i + 1}. ${ad.page_name || ad.advertiser || 'Unknown advertiser'}`);
console.log(` Status: ${ad.ad_delivery_start_time ? 'Active since ' + ad.ad_delivery_start_time : 'Active'}`);
console.log(` Platform: ${(ad.publisher_platforms || []).join(', ') || 'Facebook'}`);
console.log(` Creative: ${(ad.ad_creative_body || ad.body || ad.text || '').substring(0, 150)}`);
if (ad.spend) {
console.log(` Spend: ${ad.spend.lower_bound || '?'} - ${ad.spend.upper_bound || '?'} ${ad.currency || 'USD'}`);
}
console.log('');
});
return ads;
}
searchFacebookAds('hubspot');
Analyze Ad Creative Patterns
Break down what a competitor's ad strategy looks like:
async function analyzeAdCreatives(query) {
const res = await fetch(
`${BASE}/facebook-ad-library?query=${encodeURIComponent(query)}`,
{ headers }
);
const ads = (await res.json()).data || [];
// Categorize by format
const formats = { image: 0, video: 0, carousel: 0, other: 0 };
const ctaTypes = {};
const headlines = [];
for (const ad of ads) {
// Format detection
const type = ad.ad_creative_link_captions?.length > 1 ? 'carousel'
: ad.ad_creative_videos?.length ? 'video'
: ad.ad_creative_bodies?.length ? 'image'
: 'other';
formats[type]++;
// CTA tracking
const cta = ad.ad_creative_link_caption || ad.cta_type || 'none';
ctaTypes[cta] = (ctaTypes[cta] || 0) + 1;
// Collect headlines
const headline = ad.ad_creative_link_title || ad.title || '';
if (headline) headlines.push(headline);
}
console.log(`\nAd Creative Analysis: "${query}"`);
console.log('─'.repeat(50));
console.log(` Total ads: ${ads.length}`);
console.log(`\n Format Mix:`);
for (const [format, count] of Object.entries(formats)) {
if (count === 0) continue;
const pct = ((count / ads.length) * 100).toFixed(0);
console.log(` ${format.padEnd(12)} ${count} ads (${pct}%)`);
}
console.log(`\n Top CTAs:`);
const sortedCtas = Object.entries(ctaTypes).sort(([,a], [,b]) => b - a);
sortedCtas.slice(0, 5).forEach(([cta, count]) => {
console.log(` ${cta.padEnd(20)} ${count}`);
});
// Common headline words
const words = headlines.join(' ').toLowerCase().split(/\s+/);
const wordFreq = {};
const stopWords = new Set(['the', 'a', 'an', 'in', 'on', 'for', 'to', 'and', 'or', 'your', 'with', 'our', 'is', 'of']);
for (const w of words) {
const clean = w.replace(/[^a-z]/g, '');
if (clean.length > 2 && !stopWords.has(clean)) {
wordFreq[clean] = (wordFreq[clean] || 0) + 1;
}
}
console.log(`\n Top Headline Words:`);
Object.entries(wordFreq).sort(([,a], [,b]) => b - a).slice(0, 10).forEach(([word, count]) => {
console.log(` ${word.padEnd(15)} ${count}`);
});
return { formats, ctaTypes, headlines, total: ads.length };
}
analyzeAdCreatives('hubspot');
Google Ads Transparency Center
Google's ad transparency center lets you see ads from any advertiser across Search, YouTube, and Display:
async function searchGoogleAds(query) {
const res = await fetch(
`${BASE}/google-ad-library?query=${encodeURIComponent(query)}`,
{ headers }
);
const ads = (await res.json()).data || [];
console.log(`\nGoogle Ad Library: "${query}" — ${ads.length} ads found\n`);
ads.slice(0, 10).forEach((ad, i) => {
console.log(`${i + 1}. ${ad.advertiser_name || ad.advertiser || 'Unknown'}`);
console.log(` Format: ${ad.format || ad.type || 'N/A'}`);
console.log(` Region: ${(ad.region || ad.geo_targeting || []).join?.(', ') || 'N/A'}`);
console.log(` Last shown: ${ad.last_shown || ad.last_seen || 'N/A'}`);
console.log(` Text: ${(ad.text || ad.description || ad.creative_text || '').substring(0, 150)}`);
console.log('');
});
return ads;
}
searchGoogleAds('semrush');
LinkedIn Ad Library
LinkedIn's ad library is the newest. See what B2B competitors are running:
async function searchLinkedInAds(query) {
const res = await fetch(
`${BASE}/linkedin-ad-library?query=${encodeURIComponent(query)}`,
{ headers }
);
const ads = (await res.json()).data || [];
console.log(`\nLinkedIn Ad Library: "${query}" — ${ads.length} ads found\n`);
ads.slice(0, 10).forEach((ad, i) => {
console.log(`${i + 1}. ${ad.advertiser_name || ad.advertiser || 'Unknown'}`);
console.log(` Headline: ${ad.headline || ad.title || 'N/A'}`);
console.log(` Body: ${(ad.body || ad.text || '').substring(0, 150)}`);
console.log(` CTA: ${ad.cta || ad.call_to_action || 'N/A'}`);
console.log(` Started: ${ad.start_date || ad.created_at || 'N/A'}`);
console.log('');
});
return ads;
}
searchLinkedInAds('salesforce');
Cross-Platform Ad Comparison
Compare a competitor's ad strategy across all three platforms:
async function crossPlatformAdAnalysis(brand) {
console.log(`\nCross-Platform Ad Analysis: "${brand}"`);
console.log('═'.repeat(60));
// Facebook
const fbRes = await fetch(
`${BASE}/facebook-ad-library?query=${encodeURIComponent(brand)}`,
{ headers }
);
const fbAds = (await fbRes.json()).data || [];
// Google
const gRes = await fetch(
`${BASE}/google-ad-library?query=${encodeURIComponent(brand)}`,
{ headers }
);
const gAds = (await gRes.json()).data || [];
// LinkedIn
const liRes = await fetch(
`${BASE}/linkedin-ad-library?query=${encodeURIComponent(brand)}`,
{ headers }
);
const liAds = (await liRes.json()).data || [];
console.log(`\n Platform Active Ads`);
console.log(` ${'─'.repeat(35)}`);
console.log(` Facebook/IG ${fbAds.length}`);
console.log(` Google ${gAds.length}`);
console.log(` LinkedIn ${liAds.length}`);
console.log(` ${'─'.repeat(35)}`);
console.log(` Total ${fbAds.length + gAds.length + liAds.length}`);
// Which platform they invest most in
const biggest = [
{ platform: 'Facebook/IG', count: fbAds.length },
{ platform: 'Google', count: gAds.length },
{ platform: 'LinkedIn', count: liAds.length }
].sort((a, b) => b.count - a.count)[0];
console.log(`\n Primary ad platform: ${biggest.platform} (${biggest.count} active ads)`);
return {
brand,
facebook: fbAds.length,
google: gAds.length,
linkedin: liAds.length,
total: fbAds.length + gAds.length + liAds.length
};
}
crossPlatformAdAnalysis('hubspot');
Ad Tracking Over Time
Monitor when competitors launch and kill ads:
import os
import json
import time
import requests
from datetime import date
API_KEY = os.environ["SOCIAVAULT_API_KEY"]
BASE = "https://api.sociavault.com/v1/scrape"
HEADERS = {"X-API-Key": API_KEY}
def track_ad_changes(brands, filename="ad-tracker.json"):
"""Track competitor ad changes over time"""
# Load previous snapshot
try:
with open(filename) as f:
history = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
history = {"snapshots": []}
today = str(date.today())
snapshot = {"date": today, "brands": {}}
for brand in brands:
print(f"Scanning ads for: {brand}")
# Facebook ads
r = requests.get(f"{BASE}/facebook-ad-library", headers=HEADERS, params={"query": brand})
fb_ads = r.json().get("data", [])
time.sleep(1)
# Google ads
r = requests.get(f"{BASE}/google-ad-library", headers=HEADERS, params={"query": brand})
g_ads = r.json().get("data", [])
time.sleep(1)
snapshot["brands"][brand] = {
"facebook_count": len(fb_ads),
"google_count": len(g_ads),
"total": len(fb_ads) + len(g_ads),
"facebook_headlines": [
(ad.get("ad_creative_link_title") or ad.get("title", ""))[:100]
for ad in fb_ads[:5]
]
}
history["snapshots"].append(snapshot)
# Compare with previous
if len(history["snapshots"]) >= 2:
prev = history["snapshots"][-2]
print(f"\nChanges since {prev['date']}:")
print("-" * 50)
for brand in brands:
curr = snapshot["brands"].get(brand, {})
old = prev["brands"].get(brand, {})
fb_diff = curr.get("facebook_count", 0) - old.get("facebook_count", 0)
g_diff = curr.get("google_count", 0) - old.get("google_count", 0)
print(f"\n {brand}:")
print(f" Facebook: {curr.get('facebook_count', 0)} ({fb_diff:+d})")
print(f" Google: {curr.get('google_count', 0)} ({g_diff:+d})")
if fb_diff > 5:
print(f" ⚠️ Major Facebook ad ramp — possible new campaign")
if fb_diff < -5:
print(f" 📉 Significant ad reduction — campaign may have ended")
with open(filename, "w") as f:
json.dump(history, f, indent=2)
print(f"\nSnapshot saved: {today}")
# Run weekly
track_ad_changes(["hubspot", "salesforce", "mailchimp", "semrush"])
What to Look for in Competitor Ads
| Signal | What It Means |
|---|---|
| Many ads with same offer | They found a winner, testing variations |
| Short-lived ads (1-3 days) | Testing phase, or ads that didn't perform |
| Long-running ads (30+ days) | Proven winner, cost-effective creative |
| Sudden ad count spike | New campaign launch or seasonal push |
| Video-heavy creative mix | Investing in brand awareness |
| Direct response CTAs ("Try free") | Performance marketing focused |
| Comparison ads mentioning you | They see you as a threat |
| Job posting ads | Scaling up, possible product launch coming |
Legal Notes
All three ad libraries (Facebook, Google, LinkedIn) are publicly accessible by design. The platforms created these for transparency purposes. You're accessing the same data any person could see by visiting the ad library websites — just doing it more efficiently via API.
Get Started
Sign up free — start tracking competitor ads across all major platforms today.
Related Reading
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API. No credit card required.