DEV Community

Cover image for Searching the Facebook Ad Library Programmatically (No Scraper Needed)
Axio Api
Axio Api

Posted on Originally published at axioapi.com

Searching the Facebook Ad Library Programmatically (No Scraper Needed)

Facebook's Ad Library (facebook.com/ads/library) lets you search ads by keyword or advertiser, but there's no official API for it — Meta's Ad Library API exists but requires an app review and only covers political/social-issue ads in most regions. If you want to pull any active ad by keyword or Page ID into a script, you end up scraping the library's internal GraphQL endpoint yourself, which breaks every few months when Meta changes its payload shape.

AxioAPI wraps that endpoint behind a stable REST route so you don't maintain the scraper.

The endpoint

GET https://axioapi.com/api/v1/social/facebook/ads
Enter fullscreen mode Exit fullscreen mode

Query params (validated server-side):

param required notes
q yes, unless page_id is set keyword, up to 100 chars
page_id yes, unless q is set numeric Facebook Page ID, 5–25 digits
search_type no KEYWORD_EXACT_PHRASE, KEYWORD_UNORDERED, or PAGE (default behaves like a page lookup when page_id is present)
country no two-letter code or ALL, defaults to US
status no ACTIVE, INACTIVE, or ALL
limit no 1–50
cursor no pagination cursor from a previous response

Example: ads currently running for a brand

const API = 'https://axioapi.com/api/v1';
const headers = { Authorization: `Bearer ${process.env.AXIOAPI_KEY}`, Accept: 'application/json' };

async function searchAds(pageId, country = 'US') {
  const url = new URL(`${API}/social/facebook/ads`);
  url.searchParams.set('page_id', pageId);
  url.searchParams.set('search_type', 'PAGE');
  url.searchParams.set('country', country);
  url.searchParams.set('status', 'ACTIVE');

  const res = await fetch(url, { headers });
  if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
  return (await res.json()).data;
}

// Nike's Page ID
searchAds('15087023444').then((data) => console.log(data));
Enter fullscreen mode Exit fullscreen mode

A keyword search works the same way with q instead of page_id:

url.searchParams.set('q', 'nike');
url.searchParams.set('search_type', 'KEYWORD_EXACT_PHRASE');
Enter fullscreen mode Exit fullscreen mode

What you get back

Each ad in the response carries the usual Ad Library fields (creative text, CTA, link, start/end date) plus two derived fields AxioAPI computes for you so you don't have to:

  • days_active — how many days the ad has run (capped at "now" for still-active ads)
  • is_winning_candidate — true once days_active >= 14, a common rough signal that an ad is profitable enough for the advertiser to keep running
  • cta_type — normalized CTA text (SHOP_NOW, LEARN_MORE, …)
  • target_landing_page — hostname extracted from the ad's link URL

That last part matters if you're doing competitive research: instead of reading every ad's HTML, you can group an advertiser's active ads by landing page hostname and see which funnel they're pushing the most budget into right now.

Rate limits and caching

Results are cached server-side per query for about an hour, so repeated lookups of the same keyword or Page ID within that window don't cost you anything extra and don't hit the upstream twice. If you're building a dashboard that polls a handful of competitor Page IDs daily, this is cheap — check current pricing on the Social — Facebook API page before wiring it into anything high-volume.

If you just want to paste in a brand name and look, there's a free Facebook Ad Spy tool — no code, no account needed for the first few lookups.

Top comments (0)