Search ads by keyword
Public Facebook and Instagram ads matching a keyword or phrase, filtered by country, status, media type, platform, language and impression date. Up to 30 ads a page, with Facebook’s estimated total and a cursor to continue.
/search-ads Ads https://api.fetchlayer.dev/facebook-ad-library/search-ads Headers
Authorization string required Bearer token — your FetchLayer API key.
Parameters
query string required Keyword or phrase to search the Ad Library for.
searchType string optional keyword_unordered or keyword_exact_phrase. (default: keyword_unordered)
pageIds string[] optional Restrict the keyword search to these advertiser page ids (max 50).
country string optional Two-letter country code, or ALL. (default: ALL)
countries string[] optional Several countries at once (max 20). Overrides country.
activeStatus string optional active, inactive, or all. (default: active)
adType string optional ALL, POLITICAL_AND_ISSUE_ADS (POLITICAL is accepted for it), or a special ad category: HOUSING_ADS, EMPLOYMENT_ADS or FINANCIAL_PRODUCTS_AND_SERVICES_ADS (CREDIT_ADS is its earlier name and filters the same). Case-insensitive. (default: ALL)
mediaType string optional all, image, meme, image_and_meme, video, or none.
publisherPlatforms string[] optional FACEBOOK, INSTAGRAM, MESSENGER, AUDIENCE_NETWORK, WHATSAPP, THREADS, OCULUS, UNKNOWN.
contentLanguages string[] optional Two-letter ad language codes, for example en or es.
bylines string[] optional Political-ad disclaimers ("paid for by").
startDateFrom string optional Only ads whose impressions start on or after this YYYY-MM-DD date.
startDateTo string optional Only ads whose impressions start on or before this YYYY-MM-DD date.
isTargetedCountry boolean optional Restrict to ads targeting the country rather than merely reaching it.
limit integer optional Maximum ads returned (max 2000), or -1 for everything available. A request returns up to limit or pages × 30 ads, whichever is smaller. (default: 30)
pages integer optional Pages of up to 30 ads to collect in one request (max 100), or -1 for the maximum allowed. A very large request stops early, with hasNextPage true, a nextCursor and a note, rather than running past the response time limit. (default: 1)
cursor string optional Resume from a previous response's nextCursor. Send it with the same route, advertiser or query, country and filters; limit, pages, sortBy and format may change. A cursor from a different route, advertiser, query, country or set of filters, or one that was altered, is a 400 saying which. Cursors issued before October 2026 are still accepted, with a note, and the response carries a current nextCursor. Any other string is a 400: pass nextCursor back exactly as received.
delayMs integer optional Milliseconds to wait between pages (max 30000).
sortBy string optional start_date, end_date, total_active_time, or none. Orders the ads in this response, not the whole listing; collect more pages for a wider ordering.
sortDirection string optional asc or desc.
format string optional json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON. (default: json)
timeoutMs integer optional Time limit for the whole request, in milliseconds (1000–120000), counted from its arrival, time spent waiting in the queue included; a value outside that range is a 400. When it runs out, a paged request returns what it has with nextCursor and a note, billed for the pages it delivered; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller. Left out, the request runs as long as it needs.
Response Fields
search-ads
Search ads by keyword
filters object The filters this search actually ran with, after defaults were applied.
ads object[] The matching ads, newest data first unless sortBy says otherwise. A field Facebook does not provide is null, or [] for a list — never left out; false and 0 are real values. An ad with odd or missing fields is always returned, with those fields null.
skippedAds object[] Records in the listing that cannot be an ad at all — an empty entry, or one with no ad archive id — each with what is still known about it, and counted in notes; [] when none. Only that record is left out: the rest of the page and nextCursor are unaffected.
skippedAds[].reason string not-an-object (an empty entry where an ad belongs), missing-ad-archive-id, or unreadable (a record with an id whose contents could not be used).
skippedAds[].adArchiveId string | null The ad archive id, when the record had one.
skippedAds[].adId string | null The ad’s own id, when the record had one.
skippedAds[].pageId string | null The advertiser’s page id, when the record named one.
skippedAds[].fieldsPresent string[] The ad fields the record carried values for, by their names on an ad, for example startDate, advertiser or creative.
notes string[] Caveats about this result, such as an ad left out or a list that may be incomplete.
ads[].adArchiveId string Ad Library archive id — the handle for ad-detail and ad-media.
ads[].adLibraryUrl string Public Ad Library permalink for this ad.
ads[].isActive boolean Whether the ad was still running at the time of the request.
ads[].startDate string | null The day the ad started running, as a UTC date (YYYY-MM-DD); null when not published.
ads[].endDate string | null The day the ad stopped running, as a UTC date; for a running ad Facebook reports the current day. null when not published.
ads[].startDateUnix integer | null startDate as Unix seconds (UTC); null when not published.
ads[].endDateUnix integer | null endDate as Unix seconds (UTC); for a running ad, the current day. null when not published.
ads[].totalActiveTimeSeconds integer | null How long the ad has been live — the usual proxy for what is working. null when not published.
ads[].publisherPlatforms string[] Surfaces the ad ran on (Facebook, Instagram, Messenger, Threads…).
ads[].advertiser object The account the ad appears under: page id, name, URL, categories, like count, political byline, pageAlias, instagramUsername and instagramUsernameStatus. On a partnership ad this is partnership.postedBy.
ads[].advertiser.pageAlias string | null The account’s Facebook username; null when it publishes none.
ads[].advertiser.instagramUsername string | null The Instagram username; null when the page links none or it is not known — instagramUsernameStatus says which. Without includeProfiles most Facebook Pages on these listings are not-looked-up.
ads[].advertiser.instagramUsernameStatus string found: instagramUsername is the account’s username. not-published: the page’s own details link no Instagram account. not-looked-up: not known here — an ad names an Instagram account only when it is shown under one, so null says nothing about whether there is one; includeProfiles fills it in, as do ad-detail for the advertiser and advertiser-profile (as igUsername). With includeProfiles: lookup-failed (no answer for this account this time; asking again may fill it), skipped-cap (past the 30 accounts filled per request) or skipped-time (not filled in the time available). A username that cannot be filled never fails the request. sponsor and both partnership accounts carry it too.
ads[].sponsor object The account that ran the ad: pageId, pageName, pageUrl, pageIsDeleted, pageAlias, instagramUsername and instagramUsernameStatus. The same account as advertiser except on some partnership ads.
ads[].isPartnershipAd boolean Whether the ad carries Facebook’s “Paid partnership with” label (branded content).
ads[].partnership object | null On a paid-partnership or collaboration ad, the two accounts by position, each with pageId, pageName, pageUrl, pageIsDeleted, pageAlias, instagramUsername and instagramUsernameStatus: postedBy (A in “A with B”) and taggedPartner (B), plus runBy, brand, creator and relationship. null on every other ad.
ads[].partnership.postedBy object The account the ad appears under: A in “A with B”. To show “A with B” for any partnership ad, use postedBy as A and taggedPartner as B.
ads[].partnership.taggedPartner object The account the ad tags: B in “A with B”.
ads[].partnership.runBy string Which of the two ran (paid for) the ad: creator (postedBy), brand (taggedPartner) or other (neither). It says who ran the ad, not which party is the business.
ads[].partnership.brand object The same account as taggedPartner, named after Meta’s branded-content convention that the tagged account is the brand. That does not always hold: when a brand posts a collaboration and tags a creator, brand is the creator. Example, ad 2076260499666267: Red Bull Argentina posts and runs it, tagging the Instagram creator martibenza — postedBy and creator are Red Bull Argentina, taggedPartner and brand are martibenza, runBy is creator.
ads[].partnership.creator object The same account as postedBy; see brand on why these names are positions.
ads[].partnership.relationship string paid_partnership, for paid partnerships and Instagram collaborations alike: Facebook publishes no difference between them.
ads[].collationId string | null The version group Facebook files the ad under, or null when it files it under none (which also means a single version). ad-detail lists the versions in variations.
ads[].collationCount integer | null How many versions Facebook counts in that group for your filters; 1 means the ad runs alone in its group. null when there is no group.
ads[].creative object Title, body, caption, link, CTA, display format, plus videos, images and carousel cards. Media URLs here are Facebook’s own signed links, which expire within hours; for a download that keeps working, use the downloadUrl from ad-media.
ads[].transparency object Spend, currency, impressions and reach bands, published for political and issue ads. categories lists the special ad categories the ad declared — POLITICAL, HOUSING, EMPLOYMENT, CREDIT, possibly more than one — or [] for other ads.
adCount integer Number of ads in this response.
pagesScraped integer How many pages of up to 30 ads this response delivered — a stable count that depends only on how many ads came back. Billing follows it: 1 credit per page of up to 30 ads, and an empty result still costs the 1 credit every request pays.
pagesFetched integer A diagnostic that can vary between identical requests, so do not rely on it. It is never billed.
totalCount integer | null Facebook’s own estimate of how many ads match the whole listing. Usually present on the first page of a listing for a single country or ALL, and exact when the response reached the end of the listing. null means not known — including on some first pages — not zero.
nextCursor string | null Pass back as cursor to continue from where this response stopped — at the first ad not yet returned, also when limit ended the response partway through a page.
hasNextPage boolean Whether more results are available beyond this response.
Request
curl -X POST "https://api.fetchlayer.dev/facebook-ad-library/search-ads" \
-H "Authorization: Bearer ss-your-key" \
-H "Content-Type: application/json" \
-d '{"query":"project management software","country":"US","activeStatus":"active","mediaType":"video","limit":30}'Response
{
"adCount": 30,
"pagesScraped": 1,
"pagesFetched": 1,
"totalCount": 40599,
"hasNextPage": true,
"nextCursor": "fbal1.eyJyIjoic2VhcmNoLWFkcyIs…",
"ads": [
{
"adArchiveId": "1008774295390738",
"isActive": true,
"startDate": "2026-07-14",
"publisherPlatforms": [
"FACEBOOK",
"INSTAGRAM",
"MESSENGER",
"THREADS"
],
"advertiser": {
"pageId": "314197722000030",
"pageName": "monday.com"
},
"creative": {
"title": "Meet Your monday AI Agent",
"ctaText": "Sign up",
"linkUrl": "https://monday.com/ap/agents-for-work"
}
}
]
}