Use Facebook Ad Library Byline & Advertiser Ad Finder with Python
Pull Facebook Ad Library ads by advertiser Page ID, keyword, Ad ID, or "Paid for by" byline, with ad text, media, run dates, creative-reuse counts, and spend or impression ranges for political ads.
1. Choose the data you need
Review the published README for supported collection modes, examples, and limits. The recipe below uses the current published input definition.
2. Prepare a source-based input
This JSON contains published prefills and required-field defaults. Review every value for your task before running it; it is not a promise of successful collection.
{
"adActiveStatus": "active",
"adType": "all",
"includeEuDetails": false,
"maxItems": 3,
"mediaType": "all",
"mode": "search",
"onlyTotal": false,
"rehostMedia": false,
"resultsPerSearch": 3,
"searchTerms": [
"coffee"
],
"searchType": "keyword_unordered",
"sortBy": "relevance"
}
Download input.example.json and save your reviewed copy as input.json.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | required | What to scrape. Leave empty to process every target list you filled in (searchTerms, pageIds, adIds, bylines) in one run. |
searchTerms | array | optional | Keywords to search for in the Ad Library, one search per term. Example: ["coffee", "nike"]. |
pageIds | array | optional | Facebook Page IDs to fetch all ads from (numeric IDs, or URLs containing view_all_page_id= or profile.php?id=). Each page is searched separately. |
adIds | array | optional | Ad Library IDs to fetch directly (numeric IDs or Ads Library URLs containing ?id=). All other filters are ignored in this mode. |
bylines | array | optional | Funding-entity / committee names from the "Paid for by" disclaimer on political and issue ads. The actor tries the exact-cased name, retries the original casing, and re-checks each returned ad's byline client-side. Non-EU targets search the political & issue archive; EU/EEA targets use the all-ad-types EU DSA stream (the political archive returns zero there) and may return no byline match because Meta does not always expose it. |
country | string | optional | Country to search ads in, or ALL for every country. Ignored when the Countries multi-select below is set. |
countries | array | optional | One or more country codes, searched together as a union (unlike the single Country field). Takes precedence over Country when set. |
adActiveStatus | string | optional | Filter by ad active status. |
adType | string | optional | Filter by ad category. Note: the political-and-issue archive excludes EU/EEA countries, so EU political searches automatically use All Types (EU transparency stream). |
mediaType | string | optional | Filter by the ad's creative media type. `meme` is applied server-side only; Meta's payload has no meme marker, so output `media_type` is always image, video or none. |
publisherPlatforms | array | optional | Only return ads shown on these platforms. Leave empty for all platforms. |
contentLanguages | array | optional | Only return ads whose creative is written in one of these languages. 2-letter ISO 639-1 codes; leave empty for every language. |
searchType | string | optional | How keyword search terms are matched (mode=search only). |
startDate | string | optional | Only include ads that had impressions on or after this date (YYYY-MM-DD). Combined with End Date it forms a delivery window. |
endDate | string | optional | Only include ads that had impressions on or before this date (YYYY-MM-DD). |
sortBy | string | optional | Order results by relevance (Facebook's default) or by total impressions. |
resultsPerSearch | integer | optional | Maximum number of ads to extract per search term / page / ad / byline. |
maxItems | integer | optional | Stop the whole run after this many ads, across all search targets. |
includeEuDetails | boolean | optional | Fetch per-ad detail data: EU total reach, age/country/gender reach breakdown, targeting, payer/beneficiary, advertiser Instagram profile and page About. Adds one extra request per ad. |
rehostMedia | boolean | optional | Copy each ad's primary media (up to 15 MB) into this run's key-value store and output the permanent URL (Facebook's own media URLs expire after a few days). The original signed URL is kept in media_url_original; media_rehost_status records rehosted/disabled/too_large/download_failed/kv_failed. Arrays, carousel cards and Page profile/cover URLs stay signed. |
onlyTotal | boolean | optional | Skip ad scraping and return one total per search target per country (one lightweight page request per country, no browser). Counts respect the keyword, country, status, ad type, media type and date window; Facebook caps displayed totals at 50,001 (50,000+). Not available for byline or direct ad-ID targets, which get an unsupported_total diagnostic. |
3. Start an Actor run
Set APIFY_TOKEN in your environment. Python 3.10 or newer is sufficient; this recipe uses no third-party packages.
Execution may incur charges. Review current pricing on Apify. The request asks for a 120-second timeout and a charge limit; these settings are subject to Apify’s pricing and do not guarantee an all-inclusive spending cap.
import json
import os
import urllib.request
# Save the schema-derived example as input.json; review and edit it first.
with open("input.json", encoding="utf-8") as stream:
actor_input = json.load(stream)
token = os.environ["APIFY_TOKEN"]
request = urllib.request.Request(
"https://api.apify.com/v2/acts/Pqd4W4qhGgUDHPaGH/runs?timeout=120&maxTotalChargeUsd=0.50",
data=json.dumps(actor_input).encode("utf-8"),
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"},
method="POST",
)
# This starts a potentially billable run. Do not automatically retry this POST.
with urllib.request.urlopen(request, timeout=40) as response:
run = json.load(response)["data"]
print("Run ID:", run["id"])
print("Status:", run["status"])
# Inspect and download results in Apify Console once the run succeeds.
4. Inspect the actual results
Open the run in Apify Console and wait for a successful completion. Use the published output schema to locate results and the dataset schema to understand declared views. Missing or optional record fields must not be treated as guaranteed values.
One record per Facebook Ad Library ad: creative text, media, run dates, platform placements, creative reuse, advertiser context, and political/EU spend, impression and reach data where Meta publishes it. Fields the source does not provide for an ad are omitted.
Questions before you run
Which inputs are required?
The published required fields are mode
What does this guide verify?
The fields, prefills, and schema links are rendered from the published build. This is a usage recipe, not a paid live extraction test. Source availability and collection results can vary.
What if the run request times out?
Check Apify Console before retrying. The first request may already have created a run. Do not automatically repeat a run-creation POST.
Generated from source build m9SEVLoISWJhDLniO and its README and schemas. Source changes regenerate this guide; no third-party editorial claims are inferred.