Ad Intel: Google, Meta & TikTok Ad Library Monitor avatar

Ad Intel: Google, Meta & TikTok Ad Library Monitor

Pricing

from $1.00 / 1,000 google ads

Go to Apify Store
Ad Intel: Google, Meta & TikTok Ad Library Monitor

Ad Intel: Google, Meta & TikTok Ad Library Monitor

One input → Google, Meta & TikTok ad libraries (LinkedIn: beta, opt-in). Resolves brands/domains, unified schema, new/changed/stopped diffs. Pay per ad only — no start fee.

Pricing

from $1.00 / 1,000 google ads

Rating

0.0

(0)

Developer

Jeremy Lam

Jeremy Lam

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Enter a competitor's website, brand name or page URL. In one run you get every ad they show on the Google Ads Transparency Center (Search, YouTube, Display, Maps, Play, Shopping), the Meta Ad Library (Facebook, Instagram, Messenger, Audience Network, Threads), the TikTok Ads Library (ads shown in the EU/EEA, Switzerland and the UK) and, experimentally, the LinkedIn Ad Library. Everything comes back in one clean, de-duplicated schema, and each ad is flagged as new, changed or stopped since your last run.

No login. No cookies. No API keys. You pay only for the ads you get.

LinkedIn (beta): off by default, experimental, currently blocked by LinkedIn. LinkedIn's Ad Library currently answers our requests with HTTP 403, so LinkedIn usually returns no ads (and costs nothing, because you pay only per ad). It is not searched unless you add "linkedin" to Platforms; if you do, the run still succeeds and OUTPUT.errors reports the block. Google, Meta and TikTok are not affected.

Why this Actor

Ad IntelTypical ad-library Actor
Platforms per runGoogle + Meta + TikTok (LinkedIn: beta, opt-in, currently blocked by LinkedIn)One
Inputnike.com, Nike, a page URL, a page ID, an AR… ID, a LinkedIn company URL or any library URLUsually a library URL or page ID
Advertiser matchingResolves the domain or brand to the right Facebook page, the Google advertiser(s) verified by the domain their ads link to (e.g. notion.so → Notion Labs, Inc), the LinkedIn company and the TikTok advertiser. Look-alikes are dropped, and a "did you mean" list goes to OUTPUTKeyword results with other advertisers mixed in
EU transparency (DSA)Meta: EU reach plus age × gender × country reach, targeting (age, gender, locations), payer/beneficiary. TikTok: impressions by country × age × gender, targeting, audience size. LinkedIn: impressions by country, targetingUsually missing, or a separate paid add-on
Google text adsHeadline, description, display URL, sitelinks, local-ad business/category/address. Ads published only as images are read with OCRRaw preview strings or nothing
"What's new?"Built-in diff: new, changed (with the changed fields), unchanged, stoppedRe-scrape everything and diff it yourself
Cost controlHard cap per advertiser and platform, charge per ad only, no start fee, stops at your max chargeIssues report runs that ignored limits
OutputOne schema plus optional raw platform record, and 3 ready-made table viewsDifferent field names per platform

Quick start

{
"queries": ["nike.com", "notion.so", "https://www.facebook.com/nike"],
"platforms": ["google", "meta", "tiktok"],
"countries": ["US"],
"maxAdsPerPlatform": 50
}

Schedule this input daily with Output = "Only ads that are new since last run", then attach a webhook, Slack or email integration. You get an alert whenever a competitor launches a new creative.

Accepted queries

You typeGoogleMetaLinkedIn (beta, opt-in)TikTok
nike.comads for that domain + advertisers whose ads link to the brand's domains (verified)resolves the Facebook page linking to nike.comcompany whose name exactly matches "nike"advertiser named "Nike" (TikTok advertiser search)
Notion Labsadvertiser-name lookup with domain verificationpage-name match (or set treat queries as keywords for full-text search)exact company-name matchadvertiser search, keyword fallback optional
AR16735076323512287233 / adstransparency.google.com/advertiser/AR…that advertiser–––
https://www.facebook.com/nike or 15087023444–that page––
https://www.facebook.com/ads/library/?…–that exact search, all filters kept––
https://www.linkedin.com/company/hubspot/––that company (exact name)–
https://www.linkedin.com/ad-library/search?…––that exact search–
https://library.tiktok.com/ads?…adv_biz_ids=…–––that advertiser

Output

Each dataset item is one ad. Fields that a platform doesn't publish are null, never invented.

FieldGoogleMetaLinkedIn (beta)
id (platform:adId, stable)✓✓✓
advertiser.name / id / url✓✓✓
advertiser.payer (paid for by)–✓ when shown✓
status active/inactive✓ (last shown ≤2 days ago)✓✓ when dates shown
formattext/image/videoimage/video/carousel/…image/video/carousel/document/…
firstShown, lastShown, daysActive✓✓✓ (EU-served ads)
headline, body, description, ctaparsed from the preview✓✓
landingUrls, displayUrldisplay domain✓✓
images, videos, thumbnail✓ (YouTube links for video)✓✓
variants✓✓ (collation / cards)✓
publisherPlatformssearch/youtube/maps/play/shoppingfacebook/instagram/…linkedin
countries✓when Meta lists them✓ (impression share)
impressions (+ byCountry, per surface)✓ rangeswhen shown (political/EU)✓ total + share by country
spend–✓ (political/issue ads)–
reach.eu–when shown–
targetingEU DSA flags (raw)–language, location, targeting parameters targeted/excluded
change.status (+ changedFields, firstSeenAt)✓✓✓
storedMedia (with Download images)✓✓✓
raw (with Include raw)search + detail recordsfull Ad Library recordlabels

The run also writes an OUTPUT record to the key-value store. It holds counts per platform and per change status, the advertiser each query resolved to, each platform's timing and status, and any errors. Webhooks and agents can read that one record instead of the whole dataset.

Sample item (real output, trimmed)

{
"id": "meta:1107386451952079", "platform": "meta", "adId": "1107386451952079",
"adLibraryUrl": "https://www.facebook.com/ads/library/?id=1107386451952079",
"advertiser": { "name": "Nike", "id": "15087023444", "url": "https://www.facebook.com/nike/", "domain": "nike.com" },
"status": "active", "format": "carousel", "firstShown": "2026-09-01", "lastShown": "2026-10-14", "daysActive": 46,
"headline": "Nike Air Monarch IV", "body": "Run through summer with gear that can take the heat.", "cta": "Shop now",
"landingUrls": ["https://www.nike.com/"], "publisherPlatforms": ["facebook", "instagram"], "variants": 6,
"change": { "status": "new", "firstSeenAt": "2026-10-15T12:41:15.171Z" }
}

Monitoring and diffs

  • History lives in a named key-value store (ad-intel-monitor by default). Apify never auto-deletes named stores.
  • By default the monitor name is derived from your queries, platforms, countries, status and media type. The same input always compares against its own history. Set Monitor name to keep separate watchlists.
  • changed ignores noise. A moving lastShown date and rotating signed CDN URLs don't count as changes. For Meta dynamic product ads (isDynamic: true), only non-creative fields are compared, because Meta rotates their cards on every load.
  • stopped is reported only when a platform was scraped completely for that query. A capped or failed run never produces false "stopped" alerts. Stopped notices are free.

Pricing (pay per event, no start fee)

EventPriceExample
Google ad (with impressions, surfaces, text)$1.00 / 1,00050 ads ≈ $0.05
Meta ad$2.00 / 1,00050 ads ≈ $0.10
LinkedIn ad (with detail page; experimental, currently blocked by LinkedIn)$2.00 / 1,00050 ads ≈ $0.10
TikTok ad (with age/gender/country detail)$3.00 / 1,00050 ads ≈ $0.15
Stopped-ad notices, unchanged ads hidden by the output modefree

Max cost ≈ queries × platforms × max ads per platform × price. The Actor stops cleanly when it reaches the run's max-charge limit.

Google, Meta and TikTok connect directly (no proxy) and switch to Apify datacenter proxy only if blocked. Residential proxy is used for LinkedIn only. This keeps per-ad prices low and stable.

Use with AI agents and MCP

  • Pricing is per event only, and the Actor needs only limited permissions (it writes only to its own storages and the named monitor store), so agents can call it on a fixed budget.
  • Call it through the Apify MCP server (https://mcp.apify.com) as ad-intel-unified-ad-library, or with POST https://api.apify.com/v2/acts/<user>~ad-intel-unified-ad-library/run-sync-get-dataset-items.
  • Minimal agent input: {"queries":["competitor.com"],"maxAdsPerPlatform":20,"outputMode":"new"}. The flat JSON items need no post-processing.
  • Read OUTPUT from the default key-value store for a one-object summary.

Proxy and reliability

  • Google: public Transparency Center RPC with no proxy. If Google starts rate-limiting, the Actor switches to your proxy on its own.
  • Meta: real Chrome session on the public Ad Library page, direct connection first, Apify datacenter proxy as fallback. Meta throttles infinite-scroll pagination from data-center IPs, so the Actor reuses one browser session and loads the first page of up to ~40 filter slices (media type × platform × sort). Measured on Nike: 197 unique ads from 16 slices, against 30 from plain scrolling. EU detail calls are not throttled.
  • Google: if Google rate-limits direct requests, the Actor switches to Apify Proxy when you have it, and otherwise to a real browser session, which still gets answers.
  • TikTok: drives the public library UI in Chrome, because the API needs a page-generated signature. It paginates with View more and opens 3 ad-detail pages in parallel (about 2.4 s per ad with details).
  • LinkedIn (experimental, currently blocked by LinkedIn: requests get HTTP 403): public Ad Library HTML with browser-grade headers, 2 parallel requests, and backoff that honours Retry-After on HTTP 429. If a detail page still fails, you still get the ad from its search card (detailsMissing: true).
  • Every platform call retries with exponential backoff. One platform failing never fails the run; OUTPUT.errors explains what happened and how to fix it.

FAQ

Does it need my Facebook, Google or LinkedIn login? No. It only reads public ad libraries.

Why did Meta return fewer ads than the library shows? Meta throttles infinite-scroll pagination from data-center IPs. The Actor widens coverage with filter slices (see above); for very large advertisers, split the run by country or media type. The log reports how many ads each step added.

How are Google text ads parsed? HTML previews are parsed by template: Search ads give headline, description, display URL and sitelinks; Local ads give business, category, address, headline and description. Ads published only as a rendered image are OCR'd (extensions.textSource: "ocr", with ocrConfidence). Headlines that Google generates on the fly are flagged extensions.dynamicHeadline: true instead of being made up.

LinkedIn shows no dates or impressions for some ads? LinkedIn publishes dates, impressions and targeting for ads served in the EU (DSA). For other ads those fields are null.

TikTok outside Europe? TikTok publishes its ad library only for ads shown in the EU/EEA, Switzerland and the UK. If none of your countries is in that list, the Actor searches DE, FR, IT, ES and GB and says so in the log.

Is this legal? It collects only data the platforms publish in their public transparency libraries. Make sure your use complies with applicable laws and the platforms' terms.